mirror of https://github.com/tiangolo/fastapi.git
Merge branch 'tiangolo:master' into master
This commit is contained in:
commit
f019ca328e
|
|
@ -48,9 +48,7 @@ if __name__ == "__main__":
|
||||||
use_pr = pr
|
use_pr = pr
|
||||||
break
|
break
|
||||||
if not use_pr:
|
if not use_pr:
|
||||||
logging.error(
|
logging.error(f"No PR found for hash: {event.workflow_run.head_commit.id}")
|
||||||
f"No PR found for hash: {event.workflow_run.head_commit.id}"
|
|
||||||
)
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
github_headers = {
|
github_headers = {
|
||||||
"Authorization": f"token {settings.input_token.get_secret_value()}"
|
"Authorization": f"token {settings.input_token.get_secret_value()}"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import random
|
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
@ -54,7 +54,7 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
if pr.state == "open":
|
if pr.state == "open":
|
||||||
logging.debug(f"PR is open: {pr.number}")
|
logging.debug(f"PR is open: {pr.number}")
|
||||||
label_strs = set([label.name for label in pr.get_labels()])
|
label_strs = {label.name for label in pr.get_labels()}
|
||||||
if lang_all_label in label_strs and awaiting_label in label_strs:
|
if lang_all_label in label_strs and awaiting_label in label_strs:
|
||||||
logging.info(
|
logging.info(
|
||||||
f"This PR seems to be a language translation and awaiting reviews: {pr.number}"
|
f"This PR seems to be a language translation and awaiting reviews: {pr.number}"
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,4 @@ de: 3716
|
||||||
id: 3717
|
id: 3717
|
||||||
az: 3994
|
az: 3994
|
||||||
nl: 4701
|
nl: 4701
|
||||||
|
uz: 4883
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: ${{ env.pythonLocation }}
|
path: ${{ env.pythonLocation }}
|
||||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-docs-v2
|
key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v03
|
||||||
- name: Install Flit
|
- name: Install Flit
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
run: python3.7 -m pip install flit
|
run: python3.7 -m pip install flit
|
||||||
|
|
@ -30,7 +30,7 @@ jobs:
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
run: python3.7 -m flit install --deps production --extras doc
|
run: python3.7 -m flit install --deps production --extras doc
|
||||||
- name: Install Material for MkDocs Insiders
|
- name: Install Material for MkDocs Insiders
|
||||||
if: github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true'
|
if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
|
||||||
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
|
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
|
||||||
- name: Build Docs
|
- name: Build Docs
|
||||||
run: python3.7 ./scripts/docs.py build-all
|
run: python3.7 ./scripts/docs.py build-all
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v4.2.0
|
||||||
|
hooks:
|
||||||
|
- id: check-added-large-files
|
||||||
|
- id: check-toml
|
||||||
|
- id: check-yaml
|
||||||
|
args:
|
||||||
|
- --unsafe
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v2.32.1
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args:
|
||||||
|
- --py3-plus
|
||||||
|
- --keep-runtime-typing
|
||||||
|
- repo: https://github.com/myint/autoflake
|
||||||
|
rev: v1.4
|
||||||
|
hooks:
|
||||||
|
- id: autoflake
|
||||||
|
args:
|
||||||
|
- --recursive
|
||||||
|
- --in-place
|
||||||
|
- --remove-all-unused-imports
|
||||||
|
- --remove-unused-variables
|
||||||
|
- --expand-star-imports
|
||||||
|
- --exclude
|
||||||
|
- __init__.py
|
||||||
|
- --remove-duplicate-keys
|
||||||
|
- repo: https://github.com/pycqa/isort
|
||||||
|
rev: 5.10.1
|
||||||
|
hooks:
|
||||||
|
- id: isort
|
||||||
|
name: isort (python)
|
||||||
|
- id: isort
|
||||||
|
name: isort (cython)
|
||||||
|
types: [cython]
|
||||||
|
- id: isort
|
||||||
|
name: isort (pyi)
|
||||||
|
types: [pyi]
|
||||||
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 22.3.0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
ci:
|
||||||
|
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
|
||||||
|
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
|
||||||
14
README.md
14
README.md
|
|
@ -151,7 +151,7 @@ $ pip install "uvicorn[standard]"
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -187,7 +187,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -266,7 +266,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -277,7 +277,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -286,7 +286,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
### Automatische Dokumentation
|
### Automatische Dokumentation
|
||||||
|
|
||||||
Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standartmäßig vorhanden sind.
|
Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standardmäßig vorhanden sind.
|
||||||
|
|
||||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, bietet interaktive Exploration: testen und rufen Sie ihre API direkt vom Webbrowser auf.
|
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, bietet interaktive Exploration: testen und rufen Sie ihre API direkt vom Webbrowser auf.
|
||||||
|
|
||||||
|
|
@ -97,9 +97,9 @@ Hierdurch werden Sie nie wieder einen falschen Schlüsselnamen benutzen und spar
|
||||||
|
|
||||||
### Kompakt
|
### Kompakt
|
||||||
|
|
||||||
FastAPI nutzt für alles sensible **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brachen.
|
FastAPI nutzt für alles sinnvolle **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brauchen.
|
||||||
|
|
||||||
Aber standartmäßig, **"funktioniert einfach"** alles.
|
Aber standardmäßig, **"funktioniert einfach"** alles.
|
||||||
|
|
||||||
### Validierung
|
### Validierung
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ Aber standartmäßig, **"funktioniert einfach"** alles.
|
||||||
* Zeichenketten (`str`), mit definierter minimaler und maximaler Länge.
|
* Zeichenketten (`str`), mit definierter minimaler und maximaler Länge.
|
||||||
* Zahlen (`int`, `float`) mit minimaler und maximaler Größe, usw.
|
* Zahlen (`int`, `float`) mit minimaler und maximaler Größe, usw.
|
||||||
|
|
||||||
* Validierung für ungewögnliche Typen, wie:
|
* Validierung für ungewöhnliche Typen, wie:
|
||||||
* URL.
|
* URL.
|
||||||
* Email.
|
* Email.
|
||||||
* UUID.
|
* UUID.
|
||||||
|
|
@ -142,8 +142,8 @@ FastAPI enthält ein extrem einfaches, aber extrem mächtiges <abbr title='oft v
|
||||||
* **Automatische Umsetzung** durch FastAPI.
|
* **Automatische Umsetzung** durch FastAPI.
|
||||||
* Alle abhängigen Komponenten könnten Daten von Anfragen, **Erweiterungen der Pfadoperations-**Einschränkungen und der automatisierten Dokumentation benötigen.
|
* Alle abhängigen Komponenten könnten Daten von Anfragen, **Erweiterungen der Pfadoperations-**Einschränkungen und der automatisierten Dokumentation benötigen.
|
||||||
* **Automatische Validierung** selbst für *Pfadoperationen*-Parameter, die in den Abhängigkeiten definiert wurden.
|
* **Automatische Validierung** selbst für *Pfadoperationen*-Parameter, die in den Abhängigkeiten definiert wurden.
|
||||||
* Unterstütz komplexe Benutzerauthentifizierungssysteme, mit **Datenbankverbindungen**, usw.
|
* Unterstützt komplexe Benutzerauthentifizierungssysteme, mit **Datenbankverbindungen**, usw.
|
||||||
* **Keine Kompromisse** bei Datenbanken, Eingabemasken, usw. Sondern einfache Integration von allen.
|
* **Keine Kompromisse** bei Datenbanken, Eingabemasken, usw., sondern einfache Integration von allen.
|
||||||
|
|
||||||
### Unbegrenzte Erweiterungen
|
### Unbegrenzte Erweiterungen
|
||||||
|
|
||||||
|
|
@ -159,9 +159,9 @@ Jede Integration wurde so entworfen, dass sie einfach zu nutzen ist (mit Abhäng
|
||||||
|
|
||||||
## Starlette's Merkmale
|
## Starlette's Merkmale
|
||||||
|
|
||||||
**FastAPI** ist vollkommen kompatibel (und basiert auf) <a href="https://www.starlette.io/" class="external-link" target="_blank"><strong>Starlette</strong></a>. Das bedeutet, auch ihr eigner Starlett Quellcode funktioniert.
|
**FastAPI** ist vollkommen kompatibel (und basiert auf) <a href="https://www.starlette.io/" class="external-link" target="_blank"><strong>Starlette</strong></a>. Das bedeutet, auch ihr eigener Starlette Quellcode funktioniert.
|
||||||
|
|
||||||
`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissen direkt anwenden.
|
`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn Sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissens direkt anwenden.
|
||||||
|
|
||||||
Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nur Starlette auf Steroiden ist):
|
Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nur Starlette auf Steroiden ist):
|
||||||
|
|
||||||
|
|
@ -193,11 +193,11 @@ Mit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für d
|
||||||
* Gutes Zusammenspiel mit Ihrer/Ihrem **<abbr title="Integrierten Entwicklungsumgebung, ähnlich zu (Quellcode-)Editor">IDE</abbr>/<abbr title="Ein Programm, was Fehler im Quellcode sucht">linter</abbr>/Gehirn**:
|
* Gutes Zusammenspiel mit Ihrer/Ihrem **<abbr title="Integrierten Entwicklungsumgebung, ähnlich zu (Quellcode-)Editor">IDE</abbr>/<abbr title="Ein Programm, was Fehler im Quellcode sucht">linter</abbr>/Gehirn**:
|
||||||
* Weil Datenstrukturen von Pydantic einfach nur Instanzen ihrer definierten Klassen sind, sollten Autovervollständigung, Linting, mypy und ihre Intuition einwandfrei funktionieren.
|
* Weil Datenstrukturen von Pydantic einfach nur Instanzen ihrer definierten Klassen sind, sollten Autovervollständigung, Linting, mypy und ihre Intuition einwandfrei funktionieren.
|
||||||
* **Schnell**:
|
* **Schnell**:
|
||||||
* In <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">Vergleichen</a> ist Pydantic schneller als jede andere getestete Bibliothek.
|
* In <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">Vergleichen</a> ist Pydantic schneller als jede andere getestete Bibliothek.
|
||||||
* Validierung von **komplexen Strukturen**:
|
* Validierung von **komplexen Strukturen**:
|
||||||
* Benutzung von hierachischen Pydantic Schemata, Python `typing`’s `List` und `Dict`, etc.
|
* Benutzung von hierachischen Pydantic Schemata, Python `typing`’s `List` und `Dict`, etc.
|
||||||
* Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema.
|
* Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema.
|
||||||
* Sie können stark **verschachtelte JSON** Objekte haben und diese sind trotzdem validiert und annotiert.
|
* Sie können stark **verschachtelte JSON** Objekte haben und diese sind trotzdem validiert und annotiert.
|
||||||
* **Erweiterbar**:
|
* **Erweiterbar**:
|
||||||
* Pydantic erlaubt die Definition von eigenen Datentypen oder sie können die Validierung mit einer `validator` dekorierten Methode erweitern..
|
* Pydantic erlaubt die Definition von eigenen Datentypen oder Sie können die Validierung mit einer `validator` dekorierten Methode erweitern..
|
||||||
* 100% Testabdeckung.
|
* 100% Testabdeckung.
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -275,7 +275,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -284,7 +284,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -446,7 +446,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,17 @@
|
||||||
articles:
|
articles:
|
||||||
english:
|
english:
|
||||||
|
- author: Jean-Baptiste Rocher
|
||||||
|
author_link: https://hashnode.com/@jibrocher
|
||||||
|
link: https://dev.indooroutdoor.io/series/fastapi-react-poll-app
|
||||||
|
title: Building the Poll App From Django Tutorial With FastAPI And React
|
||||||
|
- author: Silvan Melchior
|
||||||
|
author_link: https://github.com/silvanmelchior
|
||||||
|
link: https://blog.devgenius.io/seamless-fastapi-configuration-with-confz-90949c14ea12
|
||||||
|
title: Seamless FastAPI Configuration with ConfZ
|
||||||
|
- author: Kaustubh Gupta
|
||||||
|
author_link: https://medium.com/@kaustubhgupta1828/
|
||||||
|
link: https://levelup.gitconnected.com/5-advance-features-of-fastapi-you-should-try-7c0ac7eebb3e
|
||||||
|
title: 5 Advanced Features of FastAPI You Should Try
|
||||||
- author: Kaustubh Gupta
|
- author: Kaustubh Gupta
|
||||||
author_link: https://medium.com/@kaustubhgupta1828/
|
author_link: https://medium.com/@kaustubhgupta1828/
|
||||||
link: https://www.analyticsvidhya.com/blog/2021/06/deploying-ml-models-as-api-using-fastapi-and-heroku/
|
link: https://www.analyticsvidhya.com/blog/2021/06/deploying-ml-models-as-api-using-fastapi-and-heroku/
|
||||||
|
|
@ -12,6 +24,10 @@ articles:
|
||||||
author_link: https://pystar.substack.com/
|
author_link: https://pystar.substack.com/
|
||||||
link: https://pystar.substack.com/p/how-to-create-a-fake-certificate
|
link: https://pystar.substack.com/p/how-to-create-a-fake-certificate
|
||||||
title: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI
|
title: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI
|
||||||
|
- author: Ben Gamble
|
||||||
|
author_link: https://uk.linkedin.com/in/bengamble7
|
||||||
|
link: https://ably.com/blog/realtime-ticket-booking-solution-kafka-fastapi-ably
|
||||||
|
title: Building a realtime ticket booking solution with Kafka, FastAPI, and Ably
|
||||||
- author: Shahriyar(Shako) Rzayev
|
- author: Shahriyar(Shako) Rzayev
|
||||||
author_link: https://www.linkedin.com/in/shahriyar-rzayev/
|
author_link: https://www.linkedin.com/in/shahriyar-rzayev/
|
||||||
link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series
|
link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series
|
||||||
|
|
@ -20,6 +36,10 @@ articles:
|
||||||
author_link: https://rodrigo-arenas.medium.com/
|
author_link: https://rodrigo-arenas.medium.com/
|
||||||
link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b
|
link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b
|
||||||
title: "Serve a machine learning model using Sklearn, FastAPI and Docker"
|
title: "Serve a machine learning model using Sklearn, FastAPI and Docker"
|
||||||
|
- author: Yashasvi Singh
|
||||||
|
author_link: https://hashnode.com/@aUnicornDev
|
||||||
|
link: https://aunicorndev.hashnode.dev/series/supafast-api
|
||||||
|
title: "Building an API with FastAPI and Supabase and Deploying on Deta"
|
||||||
- author: Navule Pavan Kumar Rao
|
- author: Navule Pavan Kumar Rao
|
||||||
author_link: https://www.linkedin.com/in/navule/
|
author_link: https://www.linkedin.com/in/navule/
|
||||||
link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/
|
link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/
|
||||||
|
|
@ -188,11 +208,19 @@ articles:
|
||||||
author_link: https://medium.com/@williamhayes
|
author_link: https://medium.com/@williamhayes
|
||||||
link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59
|
link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59
|
||||||
title: FastAPI/Starlette debug vs prod
|
title: FastAPI/Starlette debug vs prod
|
||||||
|
- author: Mukul Mantosh
|
||||||
|
author_link: https://twitter.com/MantoshMukul
|
||||||
|
link: https://www.jetbrains.com/pycharm/guide/tutorials/fastapi-aws-kubernetes/
|
||||||
|
title: Developing FastAPI Application using K8s & AWS
|
||||||
german:
|
german:
|
||||||
- author: Nico Axtmann
|
- author: Nico Axtmann
|
||||||
author_link: https://twitter.com/_nicoax
|
author_link: https://twitter.com/_nicoax
|
||||||
link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/
|
link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/
|
||||||
title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI
|
title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI
|
||||||
|
- author: Felix Schürmeyer
|
||||||
|
author_link: https://hellocoding.de/autor/felix-schuermeyer/
|
||||||
|
link: https://hellocoding.de/blog/coding-language/python/fastapi
|
||||||
|
title: REST-API Programmieren mittels Python und dem FastAPI Modul
|
||||||
japanese:
|
japanese:
|
||||||
- author: '@bee2'
|
- author: '@bee2'
|
||||||
author_link: https://qiita.com/bee2
|
author_link: https://qiita.com/bee2
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ But you also want it to accept new items. And when the items didn't exist before
|
||||||
|
|
||||||
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
|
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
|
||||||
|
|
||||||
```Python hl_lines="4 23"
|
```Python hl_lines="4 25"
|
||||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,8 @@ You can probably right-click each link and select an option similar to `Save lin
|
||||||
|
|
||||||
**Swagger UI** uses the files:
|
**Swagger UI** uses the files:
|
||||||
|
|
||||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
||||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
||||||
|
|
||||||
And **ReDoc** uses the file:
|
And **ReDoc** uses the file:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ To override a dependency for testing, you put as a key the original dependency (
|
||||||
|
|
||||||
And then **FastAPI** will call that override instead of the original dependency.
|
And then **FastAPI** will call that override instead of the original dependency.
|
||||||
|
|
||||||
```Python hl_lines="26-27 30"
|
```Python hl_lines="28-29 32"
|
||||||
{!../../../docs_src/dependency_testing/tutorial001.py!}
|
{!../../../docs_src/dependency_testing/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ The cashier 💁 gives you the number of your turn.
|
||||||
|
|
||||||
While you are waiting, you go with your crush 😍 and pick a table, you sit and talk with your crush 😍 for a long time (as your burgers are very fancy and take some time to prepare ✨🍔✨).
|
While you are waiting, you go with your crush 😍 and pick a table, you sit and talk with your crush 😍 for a long time (as your burgers are very fancy and take some time to prepare ✨🍔✨).
|
||||||
|
|
||||||
As you are sitting on the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨.
|
As you are sitting at the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨.
|
||||||
|
|
||||||
While waiting and talking to your crush 😍, from time to time, you check the number displayed on the counter to see if it's your turn already.
|
While waiting and talking to your crush 😍, from time to time, you check the number displayed on the counter to see if it's your turn already.
|
||||||
|
|
||||||
|
|
@ -134,7 +134,7 @@ Then, when it's your turn, you do actual "productive" work 🤓, you process the
|
||||||
|
|
||||||
But then, even though you still don't have your burgers 🍔, your work with the cashier 💁 is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready.
|
But then, even though you still don't have your burgers 🍔, your work with the cashier 💁 is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready.
|
||||||
|
|
||||||
But as you go away from the counter and sit on the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍.
|
But as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍.
|
||||||
|
|
||||||
Then the cashier 💁 says "I'm finished with doing the burgers" 🍔 by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers 🍔 because you have the number of your turn, and they have theirs.
|
Then the cashier 💁 says "I'm finished with doing the burgers" 🍔 by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers 🍔 because you have the number of your turn, and they have theirs.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ Successfully installed fastapi pydantic uvicorn
|
||||||
* Create a `main.py` file with:
|
* Create a `main.py` file with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ You can install an ASGI compatible server with:
|
||||||
|
|
||||||
## Run the Server Program
|
## Run the Server Program
|
||||||
|
|
||||||
You can then your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
|
You can then run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
|
||||||
|
|
||||||
=== "Uvicorn"
|
=== "Uvicorn"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ With **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on
|
||||||
* Plays nicely with your **<abbr title="Integrated Development Environment, similar to a code editor">IDE</abbr>/<abbr title="A program that checks for code errors">linter</abbr>/brain**:
|
* Plays nicely with your **<abbr title="Integrated Development Environment, similar to a code editor">IDE</abbr>/<abbr title="A program that checks for code errors">linter</abbr>/brain**:
|
||||||
* Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data.
|
* Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data.
|
||||||
* **Fast**:
|
* **Fast**:
|
||||||
* in <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">benchmarks</a> Pydantic is faster than all other tested libraries.
|
* in <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">benchmarks</a> Pydantic is faster than all other tested libraries.
|
||||||
* Validate **complex structures**:
|
* Validate **complex structures**:
|
||||||
* Use of hierarchical Pydantic models, Python `typing`’s `List` and `Dict`, etc.
|
* Use of hierarchical Pydantic models, Python `typing`’s `List` and `Dict`, etc.
|
||||||
* And validators allow complex data schemas to be clearly and easily defined, checked and documented as JSON Schema.
|
* And validators allow complex data schemas to be clearly and easily defined, checked and documented as JSON Schema.
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ $ pip install "uvicorn[standard]"
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -161,7 +161,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -184,7 +184,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -274,7 +274,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -283,7 +283,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,45 @@ This also means that in Python 3.10, you can use `Something | None`:
|
||||||
{!> ../../../docs_src/python_types/tutorial009_py310.py!}
|
{!> ../../../docs_src/python_types/tutorial009_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Using `Union` or `Optional`
|
||||||
|
|
||||||
|
If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view:
|
||||||
|
|
||||||
|
* 🚨 Avoid using `Optional[SomeType]`
|
||||||
|
* Instead ✨ **use `Union[SomeType, None]`** ✨.
|
||||||
|
|
||||||
|
Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required.
|
||||||
|
|
||||||
|
I think `Union[str, SomeType]` is more explicit about what it means.
|
||||||
|
|
||||||
|
It's just about the words and names. But those words can affect how you and your teammates think about the code.
|
||||||
|
|
||||||
|
As an example, let's take this function:
|
||||||
|
|
||||||
|
```Python hl_lines="1 4"
|
||||||
|
{!../../../docs_src/python_types/tutorial009c.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
say_hi() # Oh, no, this throws an error! 😱
|
||||||
|
```
|
||||||
|
|
||||||
|
The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
say_hi(name=None) # This works, None is valid 🎉
|
||||||
|
```
|
||||||
|
|
||||||
|
The good news is, once you are on Python 3.10 you won't have to worry about that, as you will be able to simply use `|` to define unions of types:
|
||||||
|
|
||||||
|
```Python hl_lines="1 4"
|
||||||
|
{!../../../docs_src/python_types/tutorial009c_py310.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
And then you won't have to worry about names like `Optional` and `Union`. 😎
|
||||||
|
|
||||||
#### Generic types
|
#### Generic types
|
||||||
|
|
||||||
These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example:
|
These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example:
|
||||||
|
|
@ -422,6 +461,9 @@ An example from the official Pydantic docs:
|
||||||
|
|
||||||
You will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
|
You will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Pydantic has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about <a href="https://pydantic-docs.helpmanual.io/usage/models/#required-optional-fields" class="external-link" target="_blank">Required Optional fields</a>.
|
||||||
|
|
||||||
## Type hints in **FastAPI**
|
## Type hints in **FastAPI**
|
||||||
|
|
||||||
**FastAPI** takes advantage of these type hints to do several things.
|
**FastAPI** takes advantage of these type hints to do several things.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,168 @@
|
||||||
## Latest Changes
|
## Latest Changes
|
||||||
|
|
||||||
|
|
||||||
|
## 0.78.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* ✨ Add support for omitting `...` as default value when declaring required parameters with:
|
||||||
|
|
||||||
|
* `Path()`
|
||||||
|
* `Query()`
|
||||||
|
* `Header()`
|
||||||
|
* `Cookie()`
|
||||||
|
* `Body()`
|
||||||
|
* `Form()`
|
||||||
|
* `File()`
|
||||||
|
|
||||||
|
New docs at [Tutorial - Query Parameters and String Validations - Make it required](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#make-it-required). PR [#4906](https://github.com/tiangolo/fastapi/pull/4906) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
|
||||||
|
Up to now, declaring a required parameter while adding additional validation or metadata needed using `...` (Ellipsis).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
from fastapi import Cookie, FastAPI, Header, Path, Query
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/items/{item_id}")
|
||||||
|
def main(
|
||||||
|
item_id: int = Path(default=..., gt=0),
|
||||||
|
query: str = Query(default=..., max_length=10),
|
||||||
|
session: str = Cookie(default=..., min_length=3),
|
||||||
|
x_trace: str = Header(default=..., title="Tracing header"),
|
||||||
|
):
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
```
|
||||||
|
|
||||||
|
...all these parameters are required because the default value is `...` (Ellipsis).
|
||||||
|
|
||||||
|
But now it's possible and supported to just omit the default value, as would be done with Pydantic fields, and the parameters would still be required.
|
||||||
|
|
||||||
|
✨ For example, this is now supported:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
from fastapi import Cookie, FastAPI, Header, Path, Query
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/items/{item_id}")
|
||||||
|
def main(
|
||||||
|
item_id: int = Path(gt=0),
|
||||||
|
query: str = Query(max_length=10),
|
||||||
|
session: str = Cookie(min_length=3),
|
||||||
|
x_trace: str = Header(title="Tracing header"),
|
||||||
|
):
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
```
|
||||||
|
|
||||||
|
To declare parameters as optional (not required), you can set a default value as always, for example using `None`:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
from typing import Union
|
||||||
|
from fastapi import Cookie, FastAPI, Header, Path, Query
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/items/{item_id}")
|
||||||
|
def main(
|
||||||
|
item_id: int = Path(gt=0),
|
||||||
|
query: Union[str, None] = Query(default=None, max_length=10),
|
||||||
|
session: Union[str, None] = Cookie(default=None, min_length=3),
|
||||||
|
x_trace: Union[str, None] = Header(default=None, title="Tracing header"),
|
||||||
|
):
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
* 📝 Add docs recommending `Union` over `Optional` and migrate source examples. New docs at [Python Types Intro - Using `Union` or `Optional`](https://fastapi.tiangolo.com/python-types/#using-union-or-optional). PR [#4908](https://github.com/tiangolo/fastapi/pull/4908) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 🎨 Fix default value as set in tutorial for Path Operations Advanced Configurations. PR [#4899](https://github.com/tiangolo/fastapi/pull/4899) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 📝 Add documentation for redefined path operations. PR [#4864](https://github.com/tiangolo/fastapi/pull/4864) by [@madkinsz](https://github.com/madkinsz).
|
||||||
|
* 📝 Updates links for Celery documentation. PR [#4736](https://github.com/tiangolo/fastapi/pull/4736) by [@sammyzord](https://github.com/sammyzord).
|
||||||
|
* ✏ Fix example code with sets in tutorial for body nested models. PR [#3030](https://github.com/tiangolo/fastapi/pull/3030) by [@hitrust](https://github.com/hitrust).
|
||||||
|
* ✏ Fix links to Pydantic docs. PR [#4670](https://github.com/tiangolo/fastapi/pull/4670) by [@kinuax](https://github.com/kinuax).
|
||||||
|
* 📝 Update docs about Swagger UI self-hosting with newer source links. PR [#4813](https://github.com/tiangolo/fastapi/pull/4813) by [@Kastakin](https://github.com/Kastakin).
|
||||||
|
* 📝 Add link to external article: Building the Poll App From Django Tutorial With FastAPI And React. PR [#4778](https://github.com/tiangolo/fastapi/pull/4778) by [@jbrocher](https://github.com/jbrocher).
|
||||||
|
* 📝 Add OpenAPI warning to "Body - Fields" docs with extra schema extensions. PR [#4846](https://github.com/tiangolo/fastapi/pull/4846) by [@ml-evs](https://github.com/ml-evs).
|
||||||
|
|
||||||
|
### Translations
|
||||||
|
|
||||||
|
* 🌐 Fix code examples in Japanese translation for `docs/ja/docs/tutorial/testing.md`. PR [#4623](https://github.com/tiangolo/fastapi/pull/4623) by [@hirotoKirimaru](https://github.com/hirotoKirimaru).
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
|
||||||
|
* ♻ Refactor dict value extraction to minimize key lookups `fastapi/utils.py`. PR [#3139](https://github.com/tiangolo/fastapi/pull/3139) by [@ShahriyarR](https://github.com/ShahriyarR).
|
||||||
|
* ✅ Add tests for required nonable parameters and body fields. PR [#4907](https://github.com/tiangolo/fastapi/pull/4907) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 👷 Fix installing Material for MkDocs Insiders in CI. PR [#4897](https://github.com/tiangolo/fastapi/pull/4897) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 👷 Add pre-commit CI instead of custom GitHub Action. PR [#4896](https://github.com/tiangolo/fastapi/pull/4896) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 👷 Add pre-commit GitHub Action workflow. PR [#4895](https://github.com/tiangolo/fastapi/pull/4895) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 📝 Add dark mode auto switch to docs based on OS preference. PR [#4869](https://github.com/tiangolo/fastapi/pull/4869) by [@ComicShrimp](https://github.com/ComicShrimp).
|
||||||
|
* 🔥 Remove un-used old pending tests, already covered in other places. PR [#4891](https://github.com/tiangolo/fastapi/pull/4891) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 🔧 Add Python formatting hooks to pre-commit. PR [#4890](https://github.com/tiangolo/fastapi/pull/4890) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 🔧 Add pre-commit with first config and first formatting pass. PR [#4888](https://github.com/tiangolo/fastapi/pull/4888) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
* 👷 Disable CI installing Material for MkDocs in forks. PR [#4410](https://github.com/tiangolo/fastapi/pull/4410) by [@dolfinus](https://github.com/dolfinus).
|
||||||
|
|
||||||
|
## 0.77.1
|
||||||
|
|
||||||
|
### Upgrades
|
||||||
|
|
||||||
|
* ⬆ Upgrade Starlette from 0.19.0 to 0.19.1. PR [#4819](https://github.com/tiangolo/fastapi/pull/4819) by [@Kludex](https://github.com/Kludex).
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
* 📝 Add link to german article: REST-API Programmieren mittels Python und dem FastAPI Modul. PR [#4624](https://github.com/tiangolo/fastapi/pull/4624) by [@fschuermeyer](https://github.com/fschuermeyer).
|
||||||
|
* 📝 Add external link: PyCharm Guide to FastAPI. PR [#4512](https://github.com/tiangolo/fastapi/pull/4512) by [@mukulmantosh](https://github.com/mukulmantosh).
|
||||||
|
* 📝 Add external link to article: Building an API with FastAPI and Supabase and Deploying on Deta. PR [#4440](https://github.com/tiangolo/fastapi/pull/4440) by [@aUnicornDev](https://github.com/aUnicornDev).
|
||||||
|
* ✏ Fix small typo in `docs/en/docs/tutorial/security/first-steps.md`. PR [#4515](https://github.com/tiangolo/fastapi/pull/4515) by [@KikoIlievski](https://github.com/KikoIlievski).
|
||||||
|
|
||||||
|
### Translations
|
||||||
|
|
||||||
|
* 🌐 Add Polish translation for `docs/pl/docs/tutorial/index.md`. PR [#4516](https://github.com/tiangolo/fastapi/pull/4516) by [@MKaczkow](https://github.com/MKaczkow).
|
||||||
|
* ✏ Fix typo in deployment. PR [#4629](https://github.com/tiangolo/fastapi/pull/4629) by [@raisulislam541](https://github.com/raisulislam541).
|
||||||
|
* 🌐 Add Portuguese translation for `docs/pt/docs/help-fastapi.md`. PR [#4583](https://github.com/tiangolo/fastapi/pull/4583) by [@mateusjs](https://github.com/mateusjs).
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
|
||||||
|
* 🔧 Add notifications in issue for Uzbek translations. PR [#4884](https://github.com/tiangolo/fastapi/pull/4884) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
|
||||||
|
## 0.77.0
|
||||||
|
|
||||||
|
### Upgrades
|
||||||
|
|
||||||
|
* ⬆ Upgrade Starlette from 0.18.0 to 0.19.0. PR [#4488](https://github.com/tiangolo/fastapi/pull/4488) by [@Kludex](https://github.com/Kludex).
|
||||||
|
* When creating an explicit `JSONResponse` the `content` argument is now required.
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
* 📝 Add external link to article: Seamless FastAPI Configuration with ConfZ. PR [#4414](https://github.com/tiangolo/fastapi/pull/4414) by [@silvanmelchior](https://github.com/silvanmelchior).
|
||||||
|
* 📝 Add external link to article: 5 Advanced Features of FastAPI You Should Try. PR [#4436](https://github.com/tiangolo/fastapi/pull/4436) by [@kaustubhgupta](https://github.com/kaustubhgupta).
|
||||||
|
* ✏ Reword to improve legibility of docs about `TestClient`. PR [#4389](https://github.com/tiangolo/fastapi/pull/4389) by [@rgilton](https://github.com/rgilton).
|
||||||
|
* 📝 Add external link to blog post about Kafka, FastAPI, and Ably. PR [#4044](https://github.com/tiangolo/fastapi/pull/4044) by [@Ugbot](https://github.com/Ugbot).
|
||||||
|
* ✏ Fix typo in `docs/en/docs/tutorial/sql-databases.md`. PR [#4875](https://github.com/tiangolo/fastapi/pull/4875) by [@wpyoga](https://github.com/wpyoga).
|
||||||
|
* ✏ Fix typo in `docs/en/docs/async.md`. PR [#4726](https://github.com/tiangolo/fastapi/pull/4726) by [@Prezu](https://github.com/Prezu).
|
||||||
|
|
||||||
|
### Translations
|
||||||
|
|
||||||
|
* 🌐 Update source example highlights for `docs/zh/docs/tutorial/query-params-str-validations.md`. PR [#4237](https://github.com/tiangolo/fastapi/pull/4237) by [@caimaoy](https://github.com/caimaoy).
|
||||||
|
* 🌐 Remove translation docs references to aiofiles as it's no longer needed since AnyIO. PR [#3594](https://github.com/tiangolo/fastapi/pull/3594) by [@alonme](https://github.com/alonme).
|
||||||
|
* ✏ 🌐 Fix typo in Portuguese translation for `docs/pt/docs/tutorial/path-params.md`. PR [#4722](https://github.com/tiangolo/fastapi/pull/4722) by [@CleoMenezesJr](https://github.com/CleoMenezesJr).
|
||||||
|
* 🌐 Fix live docs server for translations for some languages. PR [#4729](https://github.com/tiangolo/fastapi/pull/4729) by [@wakabame](https://github.com/wakabame).
|
||||||
|
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/cookie-params.md`. PR [#4112](https://github.com/tiangolo/fastapi/pull/4112) by [@lbmendes](https://github.com/lbmendes).
|
||||||
|
* 🌐 Fix French translation for `docs/tutorial/body.md`. PR [#4332](https://github.com/tiangolo/fastapi/pull/4332) by [@Smlep](https://github.com/Smlep).
|
||||||
|
* 🌐 Add Japanese translation for `docs/ja/docs/advanced/conditional-openapi.md`. PR [#2631](https://github.com/tiangolo/fastapi/pull/2631) by [@sh0nk](https://github.com/sh0nk).
|
||||||
|
* 🌐 Fix Japanese translation of `docs/ja/docs/tutorial/body.md`. PR [#3062](https://github.com/tiangolo/fastapi/pull/3062) by [@a-takahashi223](https://github.com/a-takahashi223).
|
||||||
|
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/background-tasks.md`. PR [#2170](https://github.com/tiangolo/fastapi/pull/2170) by [@izaguerreiro](https://github.com/izaguerreiro).
|
||||||
|
* 🌐 Add Portuguese translation for `docs/deployment/deta.md`. PR [#4442](https://github.com/tiangolo/fastapi/pull/4442) by [@lsglucas](https://github.com/lsglucas).
|
||||||
|
* 🌐 Add Russian translation for `docs/async.md`. PR [#4036](https://github.com/tiangolo/fastapi/pull/4036) by [@Winand](https://github.com/Winand).
|
||||||
|
* 🌐 Add Portuguese translation for `docs/tutorial/body.md`. PR [#3960](https://github.com/tiangolo/fastapi/pull/3960) by [@leandrodesouzadev](https://github.com/leandrodesouzadev).
|
||||||
|
* 🌐 Add Portuguese translation of `tutorial/extra-data-types.md`. PR [#4077](https://github.com/tiangolo/fastapi/pull/4077) by [@luccasmmg](https://github.com/luccasmmg).
|
||||||
|
* 🌐 Update German translation for `docs/features.md`. PR [#3905](https://github.com/tiangolo/fastapi/pull/3905) by [@jomue](https://github.com/jomue).
|
||||||
|
|
||||||
## 0.76.0
|
## 0.76.0
|
||||||
|
|
||||||
### Upgrades
|
### Upgrades
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ You can see more details in <a href="https://www.starlette.io/background/" class
|
||||||
|
|
||||||
## Caveat
|
## Caveat
|
||||||
|
|
||||||
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="https://docs.celeryproject.org" class="external-link" target="_blank">Celery</a>.
|
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
|
||||||
|
|
||||||
They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
|
They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,10 @@ You can declare extra information in `Field`, `Query`, `Body`, etc. And it will
|
||||||
|
|
||||||
You will learn more about adding extra information later in the docs, when learning to declare examples.
|
You will learn more about adding extra information later in the docs, when learning to declare examples.
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
Extra keys passed to `Field` will also be present in the resulting OpenAPI schema for your application.
|
||||||
|
As these keys may not necessarily be part of the OpenAPI specification, some OpenAPI tools, for example [the OpenAPI validator](https://validator.swagger.io/), may not work with your generated schema.
|
||||||
|
|
||||||
## Recap
|
## Recap
|
||||||
|
|
||||||
You can use Pydantic's `Field` to declare extra validations and metadata for model attributes.
|
You can use Pydantic's `Field` to declare extra validations and metadata for model attributes.
|
||||||
|
|
|
||||||
|
|
@ -89,13 +89,13 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="23"
|
```Python hl_lines="22"
|
||||||
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
|
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python 3.10 and above"
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
```Python hl_lines="21"
|
```Python hl_lines="20"
|
||||||
{!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
|
{!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -126,7 +126,7 @@ Of course, you can also declare additional query parameters whenever you need, a
|
||||||
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
|
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = None
|
q: Union[str, None] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
Or in Python 3.10 and above:
|
Or in Python 3.10 and above:
|
||||||
|
|
@ -139,7 +139,7 @@ For example:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="28"
|
```Python hl_lines="27"
|
||||||
{!> ../../../docs_src/body_multiple_params/tutorial004.py!}
|
{!> ../../../docs_src/body_multiple_params/tutorial004.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -152,7 +152,6 @@ For example:
|
||||||
!!! info
|
!!! info
|
||||||
`Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later.
|
`Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later.
|
||||||
|
|
||||||
|
|
||||||
## Embed a single body parameter
|
## Embed a single body parameter
|
||||||
|
|
||||||
Let's say you only have a single `item` body parameter from a Pydantic model `Item`.
|
Let's say you only have a single `item` body parameter from a Pydantic model `Item`.
|
||||||
|
|
@ -162,7 +161,7 @@ By default, **FastAPI** will then expect its body directly.
|
||||||
But if you want it to expect a JSON with a key `item` and inside of it the model contents, as it does when you declare extra body parameters, you can use the special `Body` parameter `embed`:
|
But if you want it to expect a JSON with a key `item` and inside of it the model contents, as it does when you declare extra body parameters, you can use the special `Body` parameter `embed`:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
item: Item = Body(..., embed=True)
|
item: Item = Body(embed=True)
|
||||||
```
|
```
|
||||||
|
|
||||||
as in:
|
as in:
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ The function parameters will be recognized as follows:
|
||||||
!!! note
|
!!! note
|
||||||
FastAPI will know that the value of `q` is not required because of the default value `= None`.
|
FastAPI will know that the value of `q` is not required because of the default value `= None`.
|
||||||
|
|
||||||
The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
|
The `Union` in `Union[str, None]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
|
||||||
|
|
||||||
## Without Pydantic
|
## Without Pydantic
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ Pay attention to the `__init__` method used to create the instance of the class:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="8"
|
```Python hl_lines="9"
|
||||||
{!> ../../../docs_src/dependencies/tutorial001.py!}
|
{!> ../../../docs_src/dependencies/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ It is just a function that can take all the same parameters that a *path operati
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="8-9"
|
```Python hl_lines="8-11"
|
||||||
{!> ../../../docs_src/dependencies/tutorial001.py!}
|
{!> ../../../docs_src/dependencies/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ The same way you use `Body`, `Query`, etc. with your *path operation function* p
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="13 18"
|
```Python hl_lines="15 20"
|
||||||
{!> ../../../docs_src/dependencies/tutorial001.py!}
|
{!> ../../../docs_src/dependencies/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ Then we can use the dependency with:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="21"
|
```Python hl_lines="22"
|
||||||
{!> ../../../docs_src/dependencies/tutorial005.py!}
|
{!> ../../../docs_src/dependencies/tutorial005.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ Here are some of the additional data types you can use:
|
||||||
* `datetime.timedelta`:
|
* `datetime.timedelta`:
|
||||||
* A Python `datetime.timedelta`.
|
* A Python `datetime.timedelta`.
|
||||||
* In requests and responses will be represented as a `float` of total seconds.
|
* In requests and responses will be represented as a `float` of total seconds.
|
||||||
* Pydantic also allows representing it as a "ISO 8601 time diff encoding", <a href="https://pydantic-docs.helpmanual.io/#json-serialisation" class="external-link" target="_blank">see the docs for more info</a>.
|
* Pydantic also allows representing it as a "ISO 8601 time diff encoding", <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#json_encoders" class="external-link" target="_blank">see the docs for more info</a>.
|
||||||
* `frozenset`:
|
* `frozenset`:
|
||||||
* In requests and responses, treated the same as a `set`:
|
* In requests and responses, treated the same as a `set`:
|
||||||
* In requests, a list will be read, eliminating duplicates and converting it to a `set`.
|
* In requests, a list will be read, eliminating duplicates and converting it to a `set`.
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ path -> item_id
|
||||||
!!! warning
|
!!! warning
|
||||||
These are technical details that you might skip if it's not important for you now.
|
These are technical details that you might skip if it's not important for you now.
|
||||||
|
|
||||||
`RequestValidationError` is a sub-class of Pydantic's <a href="https://pydantic-docs.helpmanual.io/#error-handling" class="external-link" target="_blank">`ValidationError`</a>.
|
`RequestValidationError` is a sub-class of Pydantic's <a href="https://pydantic-docs.helpmanual.io/usage/models/#error-handling" class="external-link" target="_blank">`ValidationError`</a>.
|
||||||
|
|
||||||
**FastAPI** uses it so that, if you use a Pydantic model in `response_model`, and your data has an error, you will see the error in your log.
|
**FastAPI** uses it so that, if you use a Pydantic model in `response_model`, and your data has an error, you will see the error in your log.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names,
|
||||||
|
|
||||||
So, you can declare your function as:
|
So, you can declare your function as:
|
||||||
|
|
||||||
```Python hl_lines="8"
|
```Python hl_lines="7"
|
||||||
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
|
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ Pass `*`, as the first parameter of the function.
|
||||||
|
|
||||||
Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value.
|
Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value.
|
||||||
|
|
||||||
```Python hl_lines="8"
|
```Python hl_lines="7"
|
||||||
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
|
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,14 @@ Because *path operations* are evaluated in order, you need to make sure that the
|
||||||
|
|
||||||
Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`.
|
Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`.
|
||||||
|
|
||||||
|
Similarly, you cannot redefine a path operation:
|
||||||
|
|
||||||
|
```Python hl_lines="6 11"
|
||||||
|
{!../../../docs_src/path_params/tutorial003b.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
The first one will always be used since the path matches first.
|
||||||
|
|
||||||
## Predefined values
|
## Predefined values
|
||||||
|
|
||||||
If you have a *path operation* that receives a *path parameter*, but you want the possible valid *path parameter* values to be predefined, you can use a standard Python <abbr title="Enumeration">`Enum`</abbr>.
|
If you have a *path operation* that receives a *path parameter*, but you want the possible valid *path parameter* values to be predefined, you can use a standard Python <abbr title="Enumeration">`Enum`</abbr>.
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ Let's take this application as example:
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
The query parameter `q` is of type `Optional[str]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
|
The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
FastAPI will know that the value of `q` is not required because of the default value `= None`.
|
FastAPI will know that the value of `q` is not required because of the default value `= None`.
|
||||||
|
|
||||||
The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
|
The `Union` in `Union[str, None]` will allow your editor to give you better support and detect errors.
|
||||||
|
|
||||||
## Additional validation
|
## Additional validation
|
||||||
|
|
||||||
|
|
@ -59,24 +59,24 @@ And now use it as the default value of your parameter, setting the parameter `ma
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value.
|
As we have to replace the default value `None` in the function with `Query()`, we can now set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value.
|
||||||
|
|
||||||
So:
|
So:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = Query(None)
|
q: Union[str, None] = Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
...makes the parameter optional, the same as:
|
...makes the parameter optional, the same as:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = None
|
q: Union[str, None] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
And in Python 3.10 and above:
|
And in Python 3.10 and above:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: str | None = Query(None)
|
q: str | None = Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
...makes the parameter optional, the same as:
|
...makes the parameter optional, the same as:
|
||||||
|
|
@ -97,17 +97,17 @@ But it declares it explicitly as being a query parameter.
|
||||||
or the:
|
or the:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
= Query(None)
|
= Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
as it will use that `None` as the default value, and that way make the parameter **not required**.
|
as it will use that `None` as the default value, and that way make the parameter **not required**.
|
||||||
|
|
||||||
The `Optional` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required.
|
The `Union[str, None]` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required.
|
||||||
|
|
||||||
Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:
|
Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: str = Query(None, max_length=50)
|
q: Union[str, None] = Query(default=None, max_length=50)
|
||||||
```
|
```
|
||||||
|
|
||||||
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
|
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
|
||||||
|
|
@ -118,7 +118,7 @@ You can also add a parameter `min_length`:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="9"
|
```Python hl_lines="10"
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -134,13 +134,13 @@ You can define a <abbr title="A regular expression, regex or regexp is a sequenc
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="10"
|
```Python hl_lines="11"
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python 3.10 and above"
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
```Python hl_lines="8"
|
```Python hl_lines="9"
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -156,7 +156,7 @@ But whenever you need them and go and learn them, know that you can already use
|
||||||
|
|
||||||
## Default values
|
## Default values
|
||||||
|
|
||||||
The same way that you can pass `None` as the first argument to be used as the default value, you can pass other values.
|
The same way that you can pass `None` as the value for the `default` parameter, you can pass other values.
|
||||||
|
|
||||||
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
|
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
|
||||||
|
|
||||||
|
|
@ -178,26 +178,68 @@ q: str
|
||||||
instead of:
|
instead of:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = None
|
q: Union[str, None] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
But we are now declaring it with `Query`, for example like:
|
But we are now declaring it with `Query`, for example like:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = Query(None, min_length=3)
|
q: Union[str, None] = Query(default=None, min_length=3)
|
||||||
```
|
```
|
||||||
|
|
||||||
So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument:
|
So, when you need to declare a value as required while using `Query`, you can simply not declare a default value:
|
||||||
|
|
||||||
```Python hl_lines="7"
|
```Python hl_lines="7"
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial006.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial006.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Required with Ellipsis (`...`)
|
||||||
|
|
||||||
|
There's an alternative way to explicitly declare that a value is required. You can set the `default` parameter to the literal value `...`:
|
||||||
|
|
||||||
|
```Python hl_lines="7"
|
||||||
|
{!../../../docs_src/query_params_str_validations/tutorial006b.py!}
|
||||||
|
```
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
If you hadn't seen that `...` before: it is a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">part of Python and is called "Ellipsis"</a>.
|
If you hadn't seen that `...` before: it is a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">part of Python and is called "Ellipsis"</a>.
|
||||||
|
|
||||||
|
It is used by Pydantic and FastAPI to explicitly declare that a value is required.
|
||||||
|
|
||||||
This will let **FastAPI** know that this parameter is required.
|
This will let **FastAPI** know that this parameter is required.
|
||||||
|
|
||||||
|
### Required with `None`
|
||||||
|
|
||||||
|
You can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`.
|
||||||
|
|
||||||
|
To do that, you can declare that `None` is a valid type but still use `default=...`:
|
||||||
|
|
||||||
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
|
```Python hl_lines="8"
|
||||||
|
{!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
|
```Python hl_lines="7"
|
||||||
|
{!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about <a href="https://pydantic-docs.helpmanual.io/usage/models/#required-optional-fields" class="external-link" target="_blank">Required Optional fields</a>.
|
||||||
|
|
||||||
|
### Use Pydantic's `Required` instead of Ellipsis (`...`)
|
||||||
|
|
||||||
|
If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic:
|
||||||
|
|
||||||
|
```Python hl_lines="2 8"
|
||||||
|
{!../../../docs_src/query_params_str_validations/tutorial006d.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Remember that in most of the cases, when something is required, you can simply omit the `default` parameter, so you normally don't have to use `...` nor `Required`.
|
||||||
|
|
||||||
## Query parameter list / multiple values
|
## Query parameter list / multiple values
|
||||||
|
|
||||||
When you define a query parameter explicitly with `Query` you can also declare it to receive a list of values, or said in other way, to receive multiple values.
|
When you define a query parameter explicitly with `Query` you can also declare it to receive a list of values, or said in other way, to receive multiple values.
|
||||||
|
|
@ -315,7 +357,7 @@ You can add a `title`:
|
||||||
|
|
||||||
=== "Python 3.10 and above"
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
```Python hl_lines="7"
|
```Python hl_lines="8"
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -399,7 +441,7 @@ To exclude a query parameter from the generated OpenAPI schema (and thus, from t
|
||||||
|
|
||||||
=== "Python 3.10 and above"
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
```Python hl_lines="7"
|
```Python hl_lines="8"
|
||||||
{!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
|
{!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ Your response model could have default values, like:
|
||||||
{!> ../../../docs_src/response_model/tutorial004_py310.py!}
|
{!> ../../../docs_src/response_model/tutorial004_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
* `description: Optional[str] = None` has a default of `None`.
|
* `description: Union[str, None] = None` has a default of `None`.
|
||||||
* `tax: float = 10.5` has a default of `10.5`.
|
* `tax: float = 10.5` has a default of `10.5`.
|
||||||
* `tags: List[str] = []` as a default of an empty list: `[]`.
|
* `tags: List[str] = []` as a default of an empty list: `[]`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,13 +68,13 @@ Here we pass an `example` of the data expected in `Body()`:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="21-26"
|
```Python hl_lines="20-25"
|
||||||
{!> ../../../docs_src/schema_extra_example/tutorial003.py!}
|
{!> ../../../docs_src/schema_extra_example/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python 3.10 and above"
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
```Python hl_lines="19-24"
|
```Python hl_lines="18-23"
|
||||||
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
|
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -99,13 +99,13 @@ Each specific example `dict` in the `examples` can contain:
|
||||||
|
|
||||||
=== "Python 3.6 and above"
|
=== "Python 3.6 and above"
|
||||||
|
|
||||||
```Python hl_lines="22-48"
|
```Python hl_lines="21-47"
|
||||||
{!> ../../../docs_src/schema_extra_example/tutorial004.py!}
|
{!> ../../../docs_src/schema_extra_example/tutorial004.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "Python 3.10 and above"
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
```Python hl_lines="20-46"
|
```Python hl_lines="19-45"
|
||||||
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
|
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ When we create an instance of the `OAuth2PasswordBearer` class we pass in the `t
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
|
Here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
|
||||||
|
|
||||||
Because we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`.
|
Because we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ Not only the IDs of those items, but all the data that we defined in the Pydanti
|
||||||
|
|
||||||
Now, in the Pydantic *models* for reading, `Item` and `User`, add an internal `Config` class.
|
Now, in the Pydantic *models* for reading, `Item` and `User`, add an internal `Config` class.
|
||||||
|
|
||||||
This <a href="https://pydantic-docs.helpmanual.io/#config" class="external-link" target="_blank">`Config`</a> class is used to provide configurations to Pydantic.
|
This <a href="https://pydantic-docs.helpmanual.io/usage/model_config/" class="external-link" target="_blank">`Config`</a> class is used to provide configurations to Pydantic.
|
||||||
|
|
||||||
In the `Config` class, set the attribute `orm_mode = True`.
|
In the `Config` class, set the attribute `orm_mode = True`.
|
||||||
|
|
||||||
|
|
@ -491,7 +491,7 @@ You can find an example of Alembic in a FastAPI project in the templates from [P
|
||||||
|
|
||||||
### Create a dependency
|
### Create a dependency
|
||||||
|
|
||||||
Now use the `SessionLocal` class we created in the `sql_app/databases.py` file to create a dependency.
|
Now use the `SessionLocal` class we created in the `sql_app/database.py` file to create a dependency.
|
||||||
|
|
||||||
We need to have an independent database session/connection (`SessionLocal`) per request, use the same session through all the request and then close it after the request is finished.
|
We need to have an independent database session/connection (`SessionLocal`) per request, use the same session through all the request and then close it after the request is finished.
|
||||||
|
|
||||||
|
|
@ -616,7 +616,7 @@ And as the code related to SQLAlchemy and the SQLAlchemy models lives in separat
|
||||||
|
|
||||||
The same way, you would be able to use the same SQLAlchemy models and utilities in other parts of your code that are not related to **FastAPI**.
|
The same way, you would be able to use the same SQLAlchemy models and utilities in other parts of your code that are not related to **FastAPI**.
|
||||||
|
|
||||||
For example, in a background task worker with <a href="https://docs.celeryproject.org" class="external-link" target="_blank">Celery</a>, <a href="https://python-rq.org/" class="external-link" target="_blank">RQ</a>, or <a href="https://arq-docs.helpmanual.io/" class="external-link" target="_blank">ARQ</a>.
|
For example, in a background task worker with <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>, <a href="https://python-rq.org/" class="external-link" target="_blank">RQ</a>, or <a href="https://arq-docs.helpmanual.io/" class="external-link" target="_blank">ARQ</a>.
|
||||||
|
|
||||||
## Review all the files
|
## Review all the files
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ With it, you can use <a href="https://docs.pytest.org/" class="external-link" ta
|
||||||
|
|
||||||
Import `TestClient`.
|
Import `TestClient`.
|
||||||
|
|
||||||
Create a `TestClient` passing to it your **FastAPI** application.
|
Create a `TestClient` by passing your **FastAPI** application to it.
|
||||||
|
|
||||||
Create functions with a name that starts with `test_` (this is standard `pytest` conventions).
|
Create functions with a name that starts with `test_` (this is standard `pytest` conventions).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Pero también quieres que acepte nuevos ítems. Cuando los ítems no existan ant
|
||||||
|
|
||||||
Para conseguir esto importa `JSONResponse` y devuelve ahí directamente tu contenido, asignando el `status_code` que quieras:
|
Para conseguir esto importa `JSONResponse` y devuelve ahí directamente tu contenido, asignando el `status_code` que quieras:
|
||||||
|
|
||||||
```Python hl_lines="2 19"
|
```Python hl_lines="4 25"
|
||||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ Con **FastAPI** obtienes todas las características de **Pydantic** (dado que Fa
|
||||||
* Interactúa bien con tu **<abbr title="en inglés: Integrated Development Environment, similar a editor de código">IDE</abbr>/<abbr title="Un programa que chequea errores en el código">linter</abbr>/cerebro**:
|
* Interactúa bien con tu **<abbr title="en inglés: Integrated Development Environment, similar a editor de código">IDE</abbr>/<abbr title="Un programa que chequea errores en el código">linter</abbr>/cerebro**:
|
||||||
* Porque las estructuras de datos de Pydantic son solo <abbr title='En español: ejemplares. Aunque a veces los llaman incorrectamente "instancias"'>instances</abbr> de clases que tu defines, el auto-completado, el linting, mypy y tu intuición deberían funcionar bien con tus datos validados.
|
* Porque las estructuras de datos de Pydantic son solo <abbr title='En español: ejemplares. Aunque a veces los llaman incorrectamente "instancias"'>instances</abbr> de clases que tu defines, el auto-completado, el linting, mypy y tu intuición deberían funcionar bien con tus datos validados.
|
||||||
* **Rápido**:
|
* **Rápido**:
|
||||||
* En <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">benchmarks</a> Pydantic es más rápido que todas las otras <abbr title='Herramienta, paquete. A veces llamado "librería"'>libraries</abbr> probadas.
|
* En <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">benchmarks</a> Pydantic es más rápido que todas las otras <abbr title='Herramienta, paquete. A veces llamado "librería"'>libraries</abbr> probadas.
|
||||||
* Valida **estructuras complejas**:
|
* Valida **estructuras complejas**:
|
||||||
* Usa modelos jerárquicos de modelos de Pydantic, `typing` de Python, `List` y `Dict`, etc.
|
* Usa modelos jerárquicos de modelos de Pydantic, `typing` de Python, `List` y `Dict`, etc.
|
||||||
* Los validadores también permiten que se definan fácil y claramente schemas complejos de datos. Estos son chequeados y documentados como JSON Schema.
|
* Los validadores también permiten que se definan fácil y claramente schemas complejos de datos. Estos son chequeados y documentados como JSON Schema.
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ $ pip install uvicorn[standard]
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
@ -156,7 +156,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ Si tu código usa `async` / `await`, usa `async def`:
|
||||||
|
|
||||||
```Python hl_lines="7 12"
|
```Python hl_lines="7 12"
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
@ -178,7 +178,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -259,7 +259,7 @@ Declara el body usando las declaraciones de tipo estándares de Python gracias a
|
||||||
```Python hl_lines="2 7-10 23-25"
|
```Python hl_lines="2 7-10 23-25"
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
@ -267,7 +267,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -276,7 +276,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -439,7 +439,6 @@ Usadas por Pydantic:
|
||||||
Usados por Starlette:
|
Usados por Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Requerido si quieres usar el `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Requerido si quieres usar el `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Requerido si quieres usar `FileResponse` o `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Requerido si quieres usar la configuración por defecto de templates.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Requerido si quieres usar la configuración por defecto de templates.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Requerido si quieres dar soporte a <abbr title="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de formularios, con `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Requerido si quieres dar soporte a <abbr title="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de formularios, con `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Requerido para dar soporte a `SessionMiddleware`.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Requerido para dar soporte a `SessionMiddleware`.
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ En este caso el parámetro de la función `q` será opcional y será `None` por
|
||||||
!!! note "Nota"
|
!!! note "Nota"
|
||||||
FastAPI sabrá que `q` es opcional por el `= None`.
|
FastAPI sabrá que `q` es opcional por el `= None`.
|
||||||
|
|
||||||
El `Optional` en `Optional[str]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Optional[str]` le permitirá a tu editor ayudarte a encontrar errores en tu código.
|
El `Union` en `Union[str, None]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Union[str, None]` le permitirá a tu editor ayudarte a encontrar errores en tu código.
|
||||||
|
|
||||||
## Conversión de tipos de parámetros de query
|
## Conversión de tipos de parámetros de query
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ $ pip install "uvicorn[standard]"
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -165,7 +165,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -175,7 +175,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -267,7 +267,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -278,7 +278,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -287,7 +287,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ Ce sont les **Sponsors**. 😎
|
||||||
|
|
||||||
Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>.
|
Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>.
|
||||||
|
|
||||||
|
{% if sponsors %}
|
||||||
|
|
||||||
{% if sponsors.gold %}
|
{% if sponsors.gold %}
|
||||||
|
|
||||||
### Gold Sponsors
|
### Gold Sponsors
|
||||||
|
|
@ -141,6 +143,7 @@ Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec <a href="https:/
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
### Individual Sponsors
|
### Individual Sponsors
|
||||||
|
|
||||||
{% if github_sponsors %}
|
{% if github_sponsors %}
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ Avec **FastAPI** vous aurez toutes les fonctionnalités de **Pydantic** (comme
|
||||||
* Aide votre **<abbr title="Integrated Development Environment, il s'agit de votre éditeur de code">IDE</abbr>/<abbr title="Programme qui analyse le code à la recherche d'erreurs">linter</abbr>/cerveau**:
|
* Aide votre **<abbr title="Integrated Development Environment, il s'agit de votre éditeur de code">IDE</abbr>/<abbr title="Programme qui analyse le code à la recherche d'erreurs">linter</abbr>/cerveau**:
|
||||||
* Parce que les structures de données de pydantic consistent seulement en une instance de classe que vous définissez; l'auto-complétion, le linting, mypy et votre intuition devrait être largement suffisante pour valider vos données.
|
* Parce que les structures de données de pydantic consistent seulement en une instance de classe que vous définissez; l'auto-complétion, le linting, mypy et votre intuition devrait être largement suffisante pour valider vos données.
|
||||||
* **Rapide**:
|
* **Rapide**:
|
||||||
* Dans les <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">benchmarks</a> Pydantic est plus rapide que toutes les autres librairies testées.
|
* Dans les <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">benchmarks</a> Pydantic est plus rapide que toutes les autres librairies testées.
|
||||||
* Valide les **structures complexes**:
|
* Valide les **structures complexes**:
|
||||||
* Utilise les modèles hiérarchique de Pydantic, le `typage` Python pour les `Lists`, `Dict`, etc.
|
* Utilise les modèles hiérarchique de Pydantic, le `typage` Python pour les `Lists`, `Dict`, etc.
|
||||||
* Et les validateurs permettent aux schémas de données complexes d'être clairement et facilement définis, validés et documentés sous forme d'un schéma JSON.
|
* Et les validateurs permettent aux schémas de données complexes d'être clairement et facilement définis, validés et documentés sous forme d'un schéma JSON.
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -275,7 +275,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -284,7 +284,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -447,7 +447,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ Plus de détails sont disponibles dans <a href="https://www.starlette.io/backgro
|
||||||
|
|
||||||
## Avertissement
|
## Avertissement
|
||||||
|
|
||||||
Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que <a href="https://docs.celeryproject.org" class="external-link" target="_blank">Celery</a>.
|
Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
|
||||||
|
|
||||||
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs.
|
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ Mais vous auriez le même support de l'éditeur avec <a href="https://www.jetbra
|
||||||
<img src="/img/tutorial/body/image05.png">
|
<img src="/img/tutorial/body/image05.png">
|
||||||
|
|
||||||
!!! tip "Astuce"
|
!!! tip "Astuce"
|
||||||
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le Plugin <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>.
|
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le Plugin <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
|
||||||
|
|
||||||
Ce qui améliore le support pour les modèles Pydantic avec :
|
Ce qui améliore le support pour les modèles Pydantic avec :
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
|
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
|
||||||
|
|
||||||
```Python hl_lines="4 23"
|
```Python hl_lines="4 25"
|
||||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
# 条件付き OpenAPI
|
||||||
|
|
||||||
|
必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。
|
||||||
|
|
||||||
|
## セキュリティとAPI、およびドキュメントについて
|
||||||
|
|
||||||
|
本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*。
|
||||||
|
|
||||||
|
それは、APIのセキュリティの強化にはならず、*path operations* は依然として利用可能です。
|
||||||
|
|
||||||
|
もしセキュリティ上の欠陥がソースコードにあるならば、それは存在したままです。
|
||||||
|
|
||||||
|
ドキュメンテーションを非表示にするのは、単にあなたのAPIへのアクセス方法を難解にするだけでなく、同時にあなた自身の本番環境でのAPIのデバッグを困難にしてしまう可能性があります。単純に、 <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">Security through obscurity</a> の一つの形態として考えられるでしょう。
|
||||||
|
|
||||||
|
もしあなたのAPIのセキュリティを強化したいなら、いくつかのよりよい方法があります。例を示すと、
|
||||||
|
|
||||||
|
* リクエストボディとレスポンスのためのPydanticモデルの定義を見直す。
|
||||||
|
* 依存関係に基づきすべての必要なパーミッションとロールを設定する。
|
||||||
|
* パスワードを絶対に平文で保存しない。パスワードハッシュのみを保存する。
|
||||||
|
* PasslibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。
|
||||||
|
* そして必要なところでは、もっと細かいパーミッション制御をOAuth2スコープを使って行う。
|
||||||
|
* など
|
||||||
|
|
||||||
|
それでも、例えば本番環境のような特定の環境のみで、あるいは環境変数の設定によってAPIドキュメントをどうしても無効にしたいという、非常に特殊なユースケースがあるかもしれません。
|
||||||
|
|
||||||
|
## 設定と環境変数による条件付き OpenAPI
|
||||||
|
|
||||||
|
生成するOpenAPIとドキュメントUIの構成は、共通のPydanticの設定を使用して簡単に切り替えられます。
|
||||||
|
|
||||||
|
例えば、
|
||||||
|
|
||||||
|
```Python hl_lines="6 11"
|
||||||
|
{!../../../docs_src/conditional_openapi/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
ここでは `openapi_url` の設定を、デフォルトの `"/openapi.json"` のまま宣言しています。
|
||||||
|
|
||||||
|
そして、これを `FastAPI` appを作る際に使います。
|
||||||
|
|
||||||
|
それから、以下のように `OPENAPI_URL` という環境変数を空文字列に設定することによってOpenAPI (UIドキュメントを含む) を無効化することができます。
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ OPENAPI_URL= uvicorn main:app
|
||||||
|
|
||||||
|
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
すると、以下のように `/openapi.json`, `/docs`, `/redoc` のどのURLにアクセスしても、 `404 Not Found` エラーが返ってくるようになります。
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"detail": "Not Found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -115,6 +115,8 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴
|
||||||
|
|
||||||
彼らは、<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a> を介して私の **FastAPI** などに関する活動を支援してくれています。
|
彼らは、<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a> を介して私の **FastAPI** などに関する活動を支援してくれています。
|
||||||
|
|
||||||
|
{% if sponsors %}
|
||||||
|
|
||||||
{% if sponsors.gold %}
|
{% if sponsors.gold %}
|
||||||
|
|
||||||
### Gold Sponsors
|
### Gold Sponsors
|
||||||
|
|
@ -142,6 +144,8 @@ FastAPIには、様々なバックグラウンドの人々を歓迎する素晴
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
### Individual Sponsors
|
### Individual Sponsors
|
||||||
|
|
||||||
{% if github_sponsors %}
|
{% if github_sponsors %}
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ FastAPIには非常に使いやすく、非常に強力な<abbr title='also know
|
||||||
* ユーザーの **<abbr title = "コードエディターに似た統合開発環境">IDE</abbr>/<abbr title = "コードエラーをチェックするプログラム">リンター</abbr>/思考 とうまく連携します**:
|
* ユーザーの **<abbr title = "コードエディターに似た統合開発環境">IDE</abbr>/<abbr title = "コードエラーをチェックするプログラム">リンター</abbr>/思考 とうまく連携します**:
|
||||||
* Pydanticのデータ構造は、ユーザーが定義するクラスの単なるインスタンスであるため、オートコンプリート、リンティング、mypy、およびユーザーの直感はすべて、検証済みのデータで適切に機能するはずです。
|
* Pydanticのデータ構造は、ユーザーが定義するクラスの単なるインスタンスであるため、オートコンプリート、リンティング、mypy、およびユーザーの直感はすべて、検証済みのデータで適切に機能するはずです。
|
||||||
* **高速**:
|
* **高速**:
|
||||||
* <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">ベンチマーク</a>では、Pydanticは他のすべてのテスト済みライブラリよりも高速です。
|
* <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">ベンチマーク</a>では、Pydanticは他のすべてのテスト済みライブラリよりも高速です。
|
||||||
* **複雑な構造**を検証:
|
* **複雑な構造**を検証:
|
||||||
* 階層的なPydanticモデルや、Pythonの「`typing`」の「`list`」と「`dict`」などの利用。
|
* 階層的なPydanticモデルや、Pythonの「`typing`」の「`list`」と「`dict`」などの利用。
|
||||||
* バリデーターにより、複雑なデータスキーマを明確かつ簡単に定義、チェックし、JSONスキーマとして文書化できます。
|
* バリデーターにより、複雑なデータスキーマを明確かつ簡単に定義、チェックし、JSONスキーマとして文書化できます。
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,6 @@ Pydantic によって使用されるもの:
|
||||||
Starlette によって使用されるもの:
|
Starlette によって使用されるもの:
|
||||||
|
|
||||||
- <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - `TestClient`を使用するために必要です。
|
- <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - `TestClient`を使用するために必要です。
|
||||||
- <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - `FileResponse` または `StaticFiles`を使用したい場合は必要です。
|
|
||||||
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用する場合は必要です。
|
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用する場合は必要です。
|
||||||
- <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>`request.form()`からの変換をサポートしたい場合は必要です。
|
- <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>`request.form()`からの変換をサポートしたい場合は必要です。
|
||||||
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` サポートのためには必要です。
|
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` サポートのためには必要です。
|
||||||
|
|
|
||||||
|
|
@ -162,4 +162,4 @@ APIはほとんどの場合 **レスポンス** ボディを送らなければ
|
||||||
|
|
||||||
## Pydanticを使わない方法
|
## Pydanticを使わない方法
|
||||||
|
|
||||||
もしPydanticモデルを使用したくない場合は、**ボディ**パラメータが利用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}を確認してください。
|
もしPydanticモデルを使用したくない場合は、**Body**パラメータが利用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}を確認してください。
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
デフォルト値`None`を`Query(None)`に置き換える必要があるので、`Query`の最初の引数はデフォルト値を定義するのと同じです。
|
デフォルト値`None`を`Query(default=None)`に置き換える必要があるので、`Query`の最初の引数はデフォルト値を定義するのと同じです。
|
||||||
|
|
||||||
なので:
|
なので:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = Query(None)
|
q: Optional[str] = Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
...を以下と同じようにパラメータをオプションにします:
|
...を以下と同じようにパラメータをオプションにします:
|
||||||
|
|
@ -60,7 +60,7 @@ q: Optional[str] = None
|
||||||
もしくは:
|
もしくは:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
= Query(None)
|
= Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
そして、 `None` を利用することでクエリパラメータが必須ではないと検知します。
|
そして、 `None` を利用することでクエリパラメータが必須ではないと検知します。
|
||||||
|
|
@ -70,7 +70,7 @@ q: Optional[str] = None
|
||||||
そして、さらに多くのパラメータを`Query`に渡すことができます。この場合、文字列に適用される、`max_length`パラメータを指定します。
|
そして、さらに多くのパラメータを`Query`に渡すことができます。この場合、文字列に適用される、`max_length`パラメータを指定します。
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: str = Query(None, max_length=50)
|
q: Union[str, None] = Query(default=None, max_length=50)
|
||||||
```
|
```
|
||||||
|
|
||||||
これにより、データを検証し、データが有効でない場合は明確なエラーを表示し、OpenAPIスキーマの *path operation* にパラメータを記載します。
|
これにより、データを検証し、データが有効でない場合は明確なエラーを表示し、OpenAPIスキーマの *path operation* にパラメータを記載します。
|
||||||
|
|
@ -79,7 +79,7 @@ q: str = Query(None, max_length=50)
|
||||||
|
|
||||||
パラメータ`min_length`も追加することができます:
|
パラメータ`min_length`も追加することができます:
|
||||||
|
|
||||||
```Python hl_lines="9"
|
```Python hl_lines="10"
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial003.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ q: str = Query(None, max_length=50)
|
||||||
|
|
||||||
パラメータが一致するべき<abbr title="正規表現とは、文字列の検索パターンを定義する文字列です。">正規表現</abbr>を定義することができます:
|
パラメータが一致するべき<abbr title="正規表現とは、文字列の検索パターンを定義する文字列です。">正規表現</abbr>を定義することができます:
|
||||||
|
|
||||||
```Python hl_lines="10"
|
```Python hl_lines="11"
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial004.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial004.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -125,13 +125,13 @@ q: str
|
||||||
以下の代わりに:
|
以下の代わりに:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = None
|
q: Union[str, None] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
現在は以下の例のように`Query`で宣言しています:
|
現在は以下の例のように`Query`で宣言しています:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = Query(None, min_length=3)
|
q: Union[str, None] = Query(default=None, min_length=3)
|
||||||
```
|
```
|
||||||
|
|
||||||
そのため、`Query`を使用して必須の値を宣言する必要がある場合は、第一引数に`...`を使用することができます:
|
そのため、`Query`を使用して必須の値を宣言する必要がある場合は、第一引数に`...`を使用することができます:
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,6 @@
|
||||||
|
|
||||||
`StaticFiles` を使用して、ディレクトリから静的ファイルを自動的に提供できます。
|
`StaticFiles` を使用して、ディレクトリから静的ファイルを自動的に提供できます。
|
||||||
|
|
||||||
## `aiofiles` をインストール
|
|
||||||
|
|
||||||
まず、`aiofiles` をインストールする必要があります:
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ pip install aiofiles
|
|
||||||
|
|
||||||
---> 100%
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## `StaticFiles` の使用
|
## `StaticFiles` の使用
|
||||||
|
|
||||||
* `StaticFiles` をインポート。
|
* `StaticFiles` をインポート。
|
||||||
|
|
|
||||||
|
|
@ -74,16 +74,24 @@
|
||||||
|
|
||||||
これらの *path operation* には `X-Token` ヘッダーが必要です。
|
これらの *path operation* には `X-Token` ヘッダーが必要です。
|
||||||
|
|
||||||
```Python
|
=== "Python 3.6 and above"
|
||||||
{!../../../docs_src/app_testing/main_b.py!}
|
|
||||||
```
|
```Python
|
||||||
|
{!> ../../../docs_src/app_testing/app_b/main.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Python 3.10 and above"
|
||||||
|
|
||||||
|
```Python
|
||||||
|
{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
|
||||||
|
```
|
||||||
|
|
||||||
### 拡張版テストファイル
|
### 拡張版テストファイル
|
||||||
|
|
||||||
次に、先程のものに拡張版のテストを加えた、`test_main_b.py` を作成します。
|
次に、先程のものに拡張版のテストを加えた、`test_main_b.py` を作成します。
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
{!../../../docs_src/app_testing/test_main_b.py!}
|
{!> ../../../docs_src/app_testing/app_b/test_main.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`requests` での実現方法を検索 (Google) できます。
|
リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`requests` での実現方法を検索 (Google) できます。
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
@ -80,6 +82,7 @@ nav:
|
||||||
- advanced/additional-status-codes.md
|
- advanced/additional-status-codes.md
|
||||||
- advanced/response-directly.md
|
- advanced/response-directly.md
|
||||||
- advanced/custom-response.md
|
- advanced/custom-response.md
|
||||||
|
- advanced/conditional-openapi.md
|
||||||
- async.md
|
- async.md
|
||||||
- デプロイ:
|
- デプロイ:
|
||||||
- deployment/index.md
|
- deployment/index.md
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ $ pip install uvicorn[standard]
|
||||||
* `main.py` 파일을 만드십시오:
|
* `main.py` 파일을 만드십시오:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -158,7 +158,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -168,7 +168,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하십시오.
|
여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하십시오.
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ INFO: Application startup complete.
|
||||||
Pydantic을 이용해 파이썬 표준 타입으로 본문을 선언합니다.
|
Pydantic을 이용해 파이썬 표준 타입으로 본문을 선언합니다.
|
||||||
|
|
||||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -271,7 +271,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -280,7 +280,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -443,7 +443,6 @@ Pydantic이 사용하는:
|
||||||
Starlette이 사용하는:
|
Starlette이 사용하는:
|
||||||
|
|
||||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - `TestClient`를 사용하려면 필요.
|
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - `TestClient`를 사용하려면 필요.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - `FileResponse` 또는 `StaticFiles`를 사용하려면 필요.
|
|
||||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - 기본 템플릿 설정을 사용하려면 필요.
|
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - 기본 템플릿 설정을 사용하려면 필요.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - `request.form()`과 함께 <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"parsing"</abbr>의 지원을 원하면 필요.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - `request.form()`과 함께 <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"parsing"</abbr>의 지원을 원하면 필요.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` 지원을 위해 필요.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` 지원을 위해 필요.
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
따라서 함수를 다음과 같이 선언 할 수 있습니다:
|
따라서 함수를 다음과 같이 선언 할 수 있습니다:
|
||||||
|
|
||||||
```Python hl_lines="8"
|
```Python hl_lines="7"
|
||||||
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
|
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 <abbr title="유래: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다.
|
파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 <abbr title="유래: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다.
|
||||||
|
|
||||||
```Python hl_lines="8"
|
```Python hl_lines="7"
|
||||||
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
|
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ http://127.0.0.1:8000/items/?skip=20
|
||||||
!!! note "참고"
|
!!! note "참고"
|
||||||
FastAPI는 `q`가 `= None`이므로 선택적이라는 것을 인지합니다.
|
FastAPI는 `q`가 `= None`이므로 선택적이라는 것을 인지합니다.
|
||||||
|
|
||||||
`Optional[str]`에 있는 `Optional`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Optional[str]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다.
|
`Union[str, None]`에 있는 `Union`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Union[str, None]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다.
|
||||||
|
|
||||||
## 쿼리 매개변수 형변환
|
## 쿼리 매개변수 형변환
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ $ pip install "uvicorn[standard]"
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -165,7 +165,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -175,7 +175,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -267,7 +267,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -278,7 +278,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -287,7 +287,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ $ pip install uvicorn[standard]
|
||||||
* Utwórz plik o nazwie `main.py` z:
|
* Utwórz plik o nazwie `main.py` z:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
Jeżeli twój kod korzysta z `async` / `await`, użyj `async def`:
|
Jeżeli twój kod korzysta z `async` / `await`, użyj `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -258,7 +258,7 @@ Zmodyfikuj teraz plik `main.py`, aby otrzmywał treść (body) żądania `PUT`.
|
||||||
Zadeklaruj treść żądania, używając standardowych typów w Pythonie dzięki Pydantic.
|
Zadeklaruj treść żądania, używając standardowych typów w Pythonie dzięki Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -269,7 +269,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -278,7 +278,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Samouczek - Wprowadzenie
|
||||||
|
|
||||||
|
Ten samouczek pokaże Ci, krok po kroku, jak używać większości funkcji **FastAPI**.
|
||||||
|
|
||||||
|
Każda część korzysta z poprzednich, ale jest jednocześnie osobnym tematem. Możesz przejść bezpośrednio do każdego rozdziału, jeśli szukasz rozwiązania konkretnego problemu.
|
||||||
|
|
||||||
|
Samouczek jest tak zbudowany, żeby służył jako punkt odniesienia w przyszłości.
|
||||||
|
|
||||||
|
Możesz wracać i sprawdzać dokładnie to czego potrzebujesz.
|
||||||
|
|
||||||
|
## Wykonywanie kodu
|
||||||
|
|
||||||
|
Wszystkie fragmenty kodu mogą być skopiowane bezpośrednio i użyte (są poprawnymi i przetestowanymi plikami).
|
||||||
|
|
||||||
|
Żeby wykonać każdy przykład skopiuj kod to pliku `main.py` i uruchom `uvicorn` za pomocą:
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
**BARDZO zalecamy** pisanie bądź kopiowanie kodu, edycję, a następnie wykonywanie go lokalnie.
|
||||||
|
|
||||||
|
Użycie w Twoim edytorze jest tym, co pokazuje prawdziwe korzyści z FastAPI, pozwala zobaczyć jak mało kodu musisz napisać, wszystkie funkcje, takie jak kontrola typów, <abbr title="auto-complete, autocompletion, IntelliSense">automatyczne uzupełnianie</abbr>, itd.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Instalacja FastAPI
|
||||||
|
|
||||||
|
Jako pierwszy krok zainstaluj FastAPI.
|
||||||
|
|
||||||
|
Na potrzeby samouczka możesz zainstalować również wszystkie opcjonalne biblioteki:
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ pip install "fastapi[all]"
|
||||||
|
|
||||||
|
---> 100%
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
...wliczając w to `uvicorn`, który będzie służył jako serwer wykonujacy Twój kod.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Możesz również wykonać instalację "krok po kroku".
|
||||||
|
|
||||||
|
Prawdopodobnie zechcesz to zrobić, kiedy będziesz wdrażać swoją aplikację w środowisku produkcyjnym:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install fastapi
|
||||||
|
```
|
||||||
|
|
||||||
|
Zainstaluj też `uvicorn`, który będzie służył jako serwer:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install "uvicorn[standard]"
|
||||||
|
```
|
||||||
|
|
||||||
|
Tak samo możesz zainstalować wszystkie dodatkowe biblioteki, których chcesz użyć.
|
||||||
|
|
||||||
|
## Zaawansowany poradnik
|
||||||
|
|
||||||
|
Jest też **Zaawansowany poradnik**, który możesz przeczytać po lekturze tego **Samouczka**.
|
||||||
|
|
||||||
|
**Zaawansowany poradnik** opiera się na tym samouczku, używa tych samych pojęć, żeby pokazać Ci kilka dodatkowych funkcji.
|
||||||
|
|
||||||
|
Najpierw jednak powinieneś przeczytać **Samouczek** (czytasz go teraz).
|
||||||
|
|
||||||
|
Ten rozdział jest zaprojektowany tak, że możesz stworzyć kompletną aplikację używając tylko informacji tutaj zawartych, a następnie rozszerzać ją na różne sposoby, w zależności od potrzeb, używając kilku dodatkowych pomysłów z **Zaawansowanego poradnika**.
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
@ -54,6 +56,8 @@ nav:
|
||||||
- tr: /tr/
|
- tr: /tr/
|
||||||
- uk: /uk/
|
- uk: /uk/
|
||||||
- zh: /zh/
|
- zh: /zh/
|
||||||
|
- Samouczek:
|
||||||
|
- tutorial/index.md
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- toc:
|
- toc:
|
||||||
permalink: true
|
permalink: true
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
# Implantação FastAPI na Deta
|
||||||
|
|
||||||
|
Nessa seção você aprenderá sobre como realizar a implantação de uma aplicação **FastAPI** na <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> utilizando o plano gratuito. 🎁
|
||||||
|
|
||||||
|
Isso tudo levará aproximadamente **10 minutos**.
|
||||||
|
|
||||||
|
!!! info "Informação"
|
||||||
|
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> é uma patrocinadora do **FastAPI**. 🎉
|
||||||
|
|
||||||
|
## Uma aplicação **FastAPI** simples
|
||||||
|
|
||||||
|
* Crie e entre em um diretório para a sua aplicação, por exemplo, `./fastapideta/`.
|
||||||
|
|
||||||
|
### Código FastAPI
|
||||||
|
|
||||||
|
* Crie o arquivo `main.py` com:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
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):
|
||||||
|
return {"item_id": item_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Requisitos
|
||||||
|
|
||||||
|
Agora, no mesmo diretório crie o arquivo `requirements.txt` com:
|
||||||
|
|
||||||
|
```text
|
||||||
|
fastapi
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip "Dica"
|
||||||
|
Você não precisa instalar Uvicorn para realizar a implantação na Deta, embora provavelmente queira instalá-lo para testar seu aplicativo localmente.
|
||||||
|
|
||||||
|
### Estrutura de diretório
|
||||||
|
|
||||||
|
Agora você terá o diretório `./fastapideta/` com dois arquivos:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
└── main.py
|
||||||
|
└── requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Crie uma conta gratuita na Deta
|
||||||
|
|
||||||
|
Agora crie <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">uma conta gratuita na Deta</a>, você precisará apenas de um email e senha.
|
||||||
|
|
||||||
|
Você nem precisa de um cartão de crédito.
|
||||||
|
|
||||||
|
## Instale a CLI
|
||||||
|
|
||||||
|
Depois de ter sua conta criada, instale Deta <abbr title="Interface de Linha de Comando">CLI</abbr>:
|
||||||
|
|
||||||
|
=== "Linux, macOS"
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ curl -fsSL https://get.deta.dev/cli.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
=== "Windows PowerShell"
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Após a instalação, abra um novo terminal para que a CLI seja detectada.
|
||||||
|
|
||||||
|
Em um novo terminal, confirme se foi instalado corretamente com:
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ deta --help
|
||||||
|
|
||||||
|
Deta command line interface for managing deta micros.
|
||||||
|
Complete documentation available at https://docs.deta.sh
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
deta [flags]
|
||||||
|
deta [command]
|
||||||
|
|
||||||
|
Available Commands:
|
||||||
|
auth Change auth settings for a deta micro
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
!!! tip "Dica"
|
||||||
|
Se você tiver problemas ao instalar a CLI, verifique a <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">documentação oficial da Deta</a>.
|
||||||
|
|
||||||
|
## Login pela CLI
|
||||||
|
|
||||||
|
Agora faça login na Deta pela CLI com:
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ deta login
|
||||||
|
|
||||||
|
Please, log in from the web page. Waiting..
|
||||||
|
Logged in successfully.
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Isso abrirá um navegador da Web e autenticará automaticamente.
|
||||||
|
|
||||||
|
## Implantação com Deta
|
||||||
|
|
||||||
|
Em seguida, implante seu aplicativo com a Deta CLI:
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ deta new
|
||||||
|
|
||||||
|
Successfully created a new micro
|
||||||
|
|
||||||
|
// Notice the "endpoint" 🔍
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "fastapideta",
|
||||||
|
"runtime": "python3.7",
|
||||||
|
"endpoint": "https://qltnci.deta.dev",
|
||||||
|
"visor": "enabled",
|
||||||
|
"http_auth": "enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
Adding dependencies...
|
||||||
|
|
||||||
|
|
||||||
|
---> 100%
|
||||||
|
|
||||||
|
|
||||||
|
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Você verá uma mensagem JSON semelhante a:
|
||||||
|
|
||||||
|
```JSON hl_lines="4"
|
||||||
|
{
|
||||||
|
"name": "fastapideta",
|
||||||
|
"runtime": "python3.7",
|
||||||
|
"endpoint": "https://qltnci.deta.dev",
|
||||||
|
"visor": "enabled",
|
||||||
|
"http_auth": "enabled"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip "Dica"
|
||||||
|
Sua implantação terá um URL `"endpoint"` diferente.
|
||||||
|
|
||||||
|
## Confira
|
||||||
|
|
||||||
|
Agora, abra seu navegador na URL do `endpoint`. No exemplo acima foi `https://qltnci.deta.dev`, mas o seu será diferente.
|
||||||
|
|
||||||
|
Você verá a resposta JSON do seu aplicativo FastAPI:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"Hello": "World"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Agora vá para o `/docs` da sua API, no exemplo acima seria `https://qltnci.deta.dev/docs`.
|
||||||
|
|
||||||
|
Ele mostrará sua documentação como:
|
||||||
|
|
||||||
|
<img src="/img/deployment/deta/image01.png">
|
||||||
|
|
||||||
|
## Permitir acesso público
|
||||||
|
|
||||||
|
Por padrão, a Deta lidará com a autenticação usando cookies para sua conta.
|
||||||
|
|
||||||
|
Mas quando estiver pronto, você pode torná-lo público com:
|
||||||
|
|
||||||
|
<div class="termy">
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ deta auth disable
|
||||||
|
|
||||||
|
Successfully disabled http auth
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Agora você pode compartilhar essa URL com qualquer pessoa e elas conseguirão acessar sua API. 🚀
|
||||||
|
|
||||||
|
## HTTPS
|
||||||
|
|
||||||
|
Parabéns! Você realizou a implantação do seu app FastAPI na Deta! 🎉 🍰
|
||||||
|
|
||||||
|
Além disso, observe que a Deta lida corretamente com HTTPS para você, para que você não precise cuidar disso e tenha a certeza de que seus clientes terão uma conexão criptografada segura. ✅ 🔒
|
||||||
|
|
||||||
|
## Verifique o Visor
|
||||||
|
|
||||||
|
Na UI da sua documentação (você estará em um URL como `https://qltnci.deta.dev/docs`) envie um request para *operação de rota* `/items/{item_id}`.
|
||||||
|
|
||||||
|
Por exemplo com ID `5`.
|
||||||
|
|
||||||
|
Agora vá para <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>.
|
||||||
|
|
||||||
|
Você verá que há uma seção à esquerda chamada <abbr title="it comes from Micro(server)">"Micros"</abbr> com cada um dos seus apps.
|
||||||
|
|
||||||
|
Você verá uma aba com "Detalhes", e também a aba "Visor", vá para "Visor".
|
||||||
|
|
||||||
|
Lá você pode inspecionar as solicitações recentes enviadas ao seu aplicativo.
|
||||||
|
|
||||||
|
Você também pode editá-los e reproduzi-los novamente.
|
||||||
|
|
||||||
|
<img src="/img/deployment/deta/image02.png">
|
||||||
|
|
||||||
|
## Saiba mais
|
||||||
|
|
||||||
|
Em algum momento, você provavelmente desejará armazenar alguns dados para seu aplicativo de uma forma que persista ao longo do tempo. Para isso você pode usar <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, que também tem um generoso **nível gratuito**.
|
||||||
|
|
||||||
|
Você também pode ler mais na <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">documentação da Deta</a>.
|
||||||
|
|
||||||
|
## Conceitos de implantação
|
||||||
|
|
||||||
|
Voltando aos conceitos que discutimos em [Deployments Concepts](./concepts.md){.internal-link target=_blank}, veja como cada um deles seria tratado com a Deta:
|
||||||
|
|
||||||
|
* **HTTPS**: Realizado pela Deta, eles fornecerão um subdomínio e lidarão com HTTPS automaticamente.
|
||||||
|
* **Executando na inicialização**: Realizado pela Deta, como parte de seu serviço.
|
||||||
|
* **Reinicialização**: Realizado pela Deta, como parte de seu serviço.
|
||||||
|
* **Replicação**: Realizado pela Deta, como parte de seu serviço.
|
||||||
|
* **Memória**: Limite predefinido pela Deta, você pode contatá-los para aumentá-lo.
|
||||||
|
* **Etapas anteriores a inicialização**: Não suportado diretamente, você pode fazê-lo funcionar com o sistema Cron ou scripts adicionais.
|
||||||
|
|
||||||
|
!!! note "Nota"
|
||||||
|
O Deta foi projetado para facilitar (e gratuitamente) a implantação rápida de aplicativos simples.
|
||||||
|
|
||||||
|
Ele pode simplificar vários casos de uso, mas, ao mesmo tempo, não suporta outros, como o uso de bancos de dados externos (além do próprio sistema de banco de dados NoSQL da Deta), máquinas virtuais personalizadas, etc.
|
||||||
|
|
||||||
|
Você pode ler mais detalhes na <a href="https://docs.deta.sh/docs/micros/about/" class="external-link" target="_blank">documentação da Deta</a> para ver se é a escolha certa para você.
|
||||||
|
|
@ -191,7 +191,7 @@ Com **FastAPI** você terá todos os recursos do **Pydantic** (já que FastAPI u
|
||||||
* Vai bem com o/a seu/sua **<abbr title="Ambiente de Desenvolvimento Integrado, similar a um editor de código">IDE</abbr>/<abbr title="Um programa que confere erros de código">linter</abbr>/cérebro**:
|
* Vai bem com o/a seu/sua **<abbr title="Ambiente de Desenvolvimento Integrado, similar a um editor de código">IDE</abbr>/<abbr title="Um programa que confere erros de código">linter</abbr>/cérebro**:
|
||||||
* Como as estruturas de dados do Pydantic são apenas instâncias de classes que você define, a auto completação, _linting_, _mypy_ e a sua intuição devem funcionar corretamente com seus dados validados.
|
* Como as estruturas de dados do Pydantic são apenas instâncias de classes que você define, a auto completação, _linting_, _mypy_ e a sua intuição devem funcionar corretamente com seus dados validados.
|
||||||
* **Rápido**:
|
* **Rápido**:
|
||||||
* em <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">_benchmarks_</a>, o Pydantic é mais rápido que todas as outras bibliotecas testadas.
|
* em <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">_benchmarks_</a>, o Pydantic é mais rápido que todas as outras bibliotecas testadas.
|
||||||
* Valida **estruturas complexas**:
|
* Valida **estruturas complexas**:
|
||||||
* Use modelos hierárquicos do Pydantic, `List` e `Dict` do `typing` do Python, etc.
|
* Use modelos hierárquicos do Pydantic, `List` e `Dict` do `typing` do Python, etc.
|
||||||
* Validadores permitem que esquemas de dados complexos sejam limpos e facilmente definidos, conferidos e documentados como JSON Schema.
|
* Validadores permitem que esquemas de dados complexos sejam limpos e facilmente definidos, conferidos e documentados como JSON Schema.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
# Ajuda FastAPI - Obter Ajuda
|
||||||
|
|
||||||
|
Você gosta do **FastAPI**?
|
||||||
|
|
||||||
|
Você gostaria de ajudar o FastAPI, outros usários, e o autor?
|
||||||
|
|
||||||
|
Ou você gostaria de obter ajuda relacionada ao **FastAPI**??
|
||||||
|
|
||||||
|
Existem métodos muito simples de ajudar (A maioria das ajudas podem ser feitas com um ou dois cliques).
|
||||||
|
|
||||||
|
E também existem vários modos de se conseguir ajuda.
|
||||||
|
|
||||||
|
## Inscreva-se na newsletter
|
||||||
|
|
||||||
|
Você pode se inscrever (pouco frequente) [**FastAPI e amigos** newsletter](/newsletter/){.internal-link target=_blank} para receber atualizações:
|
||||||
|
|
||||||
|
* Notícias sobre FastAPI e amigos 🚀
|
||||||
|
* Tutoriais 📝
|
||||||
|
* Recursos ✨
|
||||||
|
* Mudanças de última hora 🚨
|
||||||
|
* Truques e dicas ✅
|
||||||
|
|
||||||
|
## Siga o FastAPI no twitter
|
||||||
|
|
||||||
|
<a href="https://twitter.com/fastapi" class="external-link" target="_blank">Siga @fastapi no **Twitter**</a> para receber as últimas notícias sobre o **FastAPI**. 🐦
|
||||||
|
|
||||||
|
## Favorite o **FastAPI** no GitHub
|
||||||
|
|
||||||
|
Você pode "favoritar" o FastAPI no GitHub (clicando na estrela no canto superior direito): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. ⭐️
|
||||||
|
|
||||||
|
Favoritando, outros usuários poderão encontrar mais facilmente e verão que já foi útil para muita gente.
|
||||||
|
|
||||||
|
## Acompanhe novos updates no repositorio do GitHub
|
||||||
|
|
||||||
|
Você pode "acompanhar" (watch) o FastAPI no GitHub (clicando no botão com um "olho" no canto superior direito): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||||
|
|
||||||
|
Podendo selecionar apenas "Novos Updates".
|
||||||
|
|
||||||
|
Fazendo isto, serão enviadas notificações (em seu email) sempre que tiver novos updates (uma nova versão) com correções de bugs e novos recursos no **FastAPI**
|
||||||
|
|
||||||
|
## Conect-se com o autor
|
||||||
|
|
||||||
|
Você pode se conectar <a href="https://tiangolo.com" class="external-link" target="_blank">comigo (Sebastián Ramírez / `tiangolo`)</a>, o autor.
|
||||||
|
|
||||||
|
Você pode:
|
||||||
|
|
||||||
|
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Me siga no **GitHub**</a>.
|
||||||
|
* Ver também outros projetos Open Source criados por mim que podem te ajudar.
|
||||||
|
* Me seguir para saber quando um novo projeto Open Source for criado.
|
||||||
|
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Me siga no **Twitter**</a>.
|
||||||
|
* Me dizer o motivo pelo o qual você está usando o FastAPI(Adoro ouvir esse tipo de comentário).
|
||||||
|
* Saber quando eu soltar novos anúncios ou novas ferramentas.
|
||||||
|
* Também é possivel <a href="https://twitter.com/fastapi" class="external-link" target="_blank">seguir o @fastapi no Twitter</a> (uma conta aparte).
|
||||||
|
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Conect-se comigo no **Linkedin**</a>.
|
||||||
|
* Saber quando eu fizer novos anúncios ou novas ferramentas (apesar de que uso o twitter com mais frequência 🤷♂).
|
||||||
|
* Ler meus artigos (ou me seguir) no <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> ou no <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
|
||||||
|
* Ficar por dentro de novas ideias, artigos, e ferramentas criadas por mim.
|
||||||
|
* Me siga para saber quando eu publicar algo novo.
|
||||||
|
|
||||||
|
## Tweete sobre **FastAPI**
|
||||||
|
|
||||||
|
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/tiangolo/fastapi" class="external-link" target="_blank">Tweete sobre o **FastAPI**</a> e compartilhe comigo e com os outros o porque de gostar do FastAPI. 🎉
|
||||||
|
|
||||||
|
Adoro ouvir sobre como o **FastAPI** é usado, o que você gosta nele, em qual projeto/empresa está sendo usado, etc.
|
||||||
|
|
||||||
|
## Vote no FastAPI
|
||||||
|
|
||||||
|
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Vote no **FastAPI** no Slant</a>.
|
||||||
|
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Vote no **FastAPI** no AlternativeTo</a>.
|
||||||
|
|
||||||
|
## Responda perguntas no GitHub
|
||||||
|
|
||||||
|
Você pode acompanhar as <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">perguntas existentes</a> e tentar ajudar outros, . 🤓
|
||||||
|
|
||||||
|
Ajudando a responder as questões de varias pessoas, você pode se tornar um [Expert em FastAPI](fastapi-people.md#experts){.internal-link target=_blank} oficial. 🎉
|
||||||
|
|
||||||
|
## Acompanhe o repositório do GitHub
|
||||||
|
|
||||||
|
Você pode "acompanhar" (watch) o FastAPI no GitHub (clicando no "olho" no canto superior direito): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||||
|
|
||||||
|
Se você selecionar "Acompanhando" (Watching) em vez de "Apenas Lançamentos" (Releases only) você receberá notificações quando alguém tiver uma nova pergunta.
|
||||||
|
|
||||||
|
Assim podendo tentar ajudar a resolver essas questões.
|
||||||
|
|
||||||
|
## Faça perguntas
|
||||||
|
|
||||||
|
É possível <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">criar uma nova pergunta</a> no repositório do GitHub, por exemplo:
|
||||||
|
|
||||||
|
* Faça uma **pergunta** ou pergunte sobre um **problema**.
|
||||||
|
* Sugira novos **recursos**.
|
||||||
|
|
||||||
|
**Nota**: Se você fizer uma pergunta, então eu gostaria de pedir que você também ajude os outros com suas respectivas perguntas. 😉
|
||||||
|
|
||||||
|
## Crie um Pull Request
|
||||||
|
|
||||||
|
É possível [contribuir](contributing.md){.internal-link target=_blank} no código fonte fazendo Pull Requests, por exemplo:
|
||||||
|
|
||||||
|
* Para corrigir um erro de digitação que você encontrou na documentação.
|
||||||
|
* Para compartilhar um artigo, video, ou podcast criados por você sobre o FastAPI <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">editando este arquivo</a>.
|
||||||
|
* Não se esqueça de adicionar o link no começo da seção correspondente.
|
||||||
|
* Para ajudar [traduzir a documentação](contributing.md#translations){.internal-link target=_blank} para sua lingua.
|
||||||
|
* Também é possivel revisar as traduções já existentes.
|
||||||
|
* Para propor novas seções na documentação.
|
||||||
|
* Para corrigir um bug/questão.
|
||||||
|
* Para adicionar um novo recurso.
|
||||||
|
|
||||||
|
## Entre no chat
|
||||||
|
|
||||||
|
Entre no 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">server de conversa do Discord</a> 👥 e conheça novas pessoas da comunidade
|
||||||
|
do FastAPI.
|
||||||
|
|
||||||
|
!!! dica
|
||||||
|
Para perguntas, pergunte nas <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">questões do GitHub</a>, lá tem um chance maior de você ser ajudado sobre o FastAPI [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}.
|
||||||
|
|
||||||
|
Use o chat apenas para outro tipo de assunto.
|
||||||
|
|
||||||
|
Também existe o <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">chat do Gitter</a>, porém ele não possuí canais e recursos avançados, conversas são mais engessadas, por isso o Discord é mais recomendado.
|
||||||
|
|
||||||
|
### Não faça perguntas no chat
|
||||||
|
|
||||||
|
Tenha em mente que os chats permitem uma "conversa mais livre", dessa forma é muito fácil fazer perguntas que são muito genéricas e dificeís de responder, assim você pode acabar não sendo respondido.
|
||||||
|
|
||||||
|
Nas questões do GitHub o template irá te guiar para que você faça a sua pergunta de um jeito mais correto, fazendo com que você receba respostas mais completas, e até mesmo que você mesmo resolva o problema antes de perguntar. E no GitHub eu garanto que sempre irei responder todas as perguntas, mesmo que leve um tempo. Eu pessoalmente não consigo fazer isso via chat. 😅
|
||||||
|
|
||||||
|
Conversas no chat não são tão fáceis de serem encontrados quanto no GitHub, então questões e respostas podem se perder dentro da conversa. E apenas as que estão nas questões do GitHub contam para você se tornar um [Expert em FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, então você receberá mais atenção nas questões do GitHub.
|
||||||
|
|
||||||
|
Por outro lado, existem milhares de usuários no chat, então tem uma grande chance de você encontrar alguém para trocar uma idéia por lá em qualquer horário. 😄
|
||||||
|
|
||||||
|
## Patrocine o autor
|
||||||
|
|
||||||
|
Você também pode ajudar o autor financeiramente (eu) através do <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>.
|
||||||
|
|
||||||
|
Lá você pode me pagar um cafézinho ☕️ como agradecimento. 😄
|
||||||
|
|
||||||
|
E você também pode se tornar um patrocinador Prata ou Ouro do FastAPI. 🏅🎉
|
||||||
|
|
||||||
|
## Patrocine as ferramente que potencializam o FastAPI
|
||||||
|
|
||||||
|
Como você viu na documentação, o FastAPI se apoia em nos gigantes, Starlette e Pydantic.
|
||||||
|
|
||||||
|
Patrocine também:
|
||||||
|
|
||||||
|
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
|
||||||
|
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Muito Obrigado! 🚀
|
||||||
|
|
@ -138,7 +138,7 @@ $ pip install uvicorn[standard]
|
||||||
* Crie um arquivo `main.py` com:
|
* Crie um arquivo `main.py` com:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -161,7 +161,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
Se seu código utiliza `async` / `await`, use `async def`:
|
Se seu código utiliza `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -253,6 +253,8 @@ Agora modifique o arquivo `main.py` para receber um corpo para uma requisição
|
||||||
Declare o corpo utilizando tipos padrão Python, graças ao Pydantic.
|
Declare o corpo utilizando tipos padrão Python, graças ao Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
@ -262,7 +264,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -271,7 +273,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -434,7 +436,6 @@ Usados por Pydantic:
|
||||||
Usados por Starlette:
|
Usados por Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Necessário se você quiser utilizar o `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Necessário se você quiser utilizar o `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Necessário se você quiser utilizar o `FileResponse` ou `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Necessário se você quiser utilizar a configuração padrão de templates.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Necessário se você quiser utilizar a configuração padrão de templates.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Necessário se você quiser suporte com <abbr title="converte uma string que chega de uma requisição HTTP para dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Necessário se você quiser suporte com <abbr title="converte uma string que chega de uma requisição HTTP para dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Necessário para suporte a `SessionMiddleware`.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Necessário para suporte a `SessionMiddleware`.
|
||||||
|
|
|
||||||
|
|
@ -313,4 +313,3 @@ O importante é que, usando tipos padrão de Python, em um único local (em vez
|
||||||
|
|
||||||
!!! info "Informação"
|
!!! info "Informação"
|
||||||
Se você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é <a href = "https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class = "external-link "target =" _ blank "> a "cheat sheet" do `mypy` </a>.
|
Se você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é <a href = "https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class = "external-link "target =" _ blank "> a "cheat sheet" do `mypy` </a>.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
# Tarefas em segundo plano
|
||||||
|
|
||||||
|
Você pode definir tarefas em segundo plano a serem executadas _ após _ retornar uma resposta.
|
||||||
|
|
||||||
|
Isso é útil para operações que precisam acontecer após uma solicitação, mas que o cliente realmente não precisa esperar a operação ser concluída para receber a resposta.
|
||||||
|
|
||||||
|
Isso inclui, por exemplo:
|
||||||
|
|
||||||
|
- Envio de notificações por email após a realização de uma ação:
|
||||||
|
- Como conectar-se a um servidor de e-mail e enviar um e-mail tende a ser "lento" (vários segundos), você pode retornar a resposta imediatamente e enviar a notificação por e-mail em segundo plano.
|
||||||
|
- Processando dados:
|
||||||
|
- Por exemplo, digamos que você receba um arquivo que deve passar por um processo lento, você pode retornar uma resposta de "Aceito" (HTTP 202) e processá-lo em segundo plano.
|
||||||
|
|
||||||
|
## Usando `BackgroundTasks`
|
||||||
|
|
||||||
|
Primeiro, importe `BackgroundTasks` e defina um parâmetro em sua _função de operação de caminho_ com uma declaração de tipo de `BackgroundTasks`:
|
||||||
|
|
||||||
|
```Python hl_lines="1 13"
|
||||||
|
{!../../../docs_src/background_tasks/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
O **FastAPI** criará o objeto do tipo `BackgroundTasks` para você e o passará como esse parâmetro.
|
||||||
|
|
||||||
|
## Criar uma função de tarefa
|
||||||
|
|
||||||
|
Crie uma função a ser executada como tarefa em segundo plano.
|
||||||
|
|
||||||
|
É apenas uma função padrão que pode receber parâmetros.
|
||||||
|
|
||||||
|
Pode ser uma função `async def` ou `def` normal, o **FastAPI** saberá como lidar com isso corretamente.
|
||||||
|
|
||||||
|
Nesse caso, a função de tarefa gravará em um arquivo (simulando o envio de um e-mail).
|
||||||
|
|
||||||
|
E como a operação de gravação não usa `async` e `await`, definimos a função com `def` normal:
|
||||||
|
|
||||||
|
```Python hl_lines="6-9"
|
||||||
|
{!../../../docs_src/background_tasks/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adicionar a tarefa em segundo plano
|
||||||
|
|
||||||
|
Dentro de sua _função de operação de caminho_, passe sua função de tarefa para o objeto _tarefas em segundo plano_ com o método `.add_task()`:
|
||||||
|
|
||||||
|
```Python hl_lines="14"
|
||||||
|
{!../../../docs_src/background_tasks/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
`.add_task()` recebe como argumentos:
|
||||||
|
|
||||||
|
- Uma função de tarefa a ser executada em segundo plano (`write_notification`).
|
||||||
|
- Qualquer sequência de argumentos que deve ser passada para a função de tarefa na ordem (`email`).
|
||||||
|
- Quaisquer argumentos nomeados que devem ser passados para a função de tarefa (`mensagem = "alguma notificação"`).
|
||||||
|
|
||||||
|
## Injeção de dependência
|
||||||
|
|
||||||
|
Usar `BackgroundTasks` também funciona com o sistema de injeção de dependência, você pode declarar um parâmetro do tipo `BackgroundTasks` em vários níveis: em uma _função de operação de caminho_, em uma dependência (confiável), em uma subdependência, etc.
|
||||||
|
|
||||||
|
O **FastAPI** sabe o que fazer em cada caso e como reutilizar o mesmo objeto, de forma que todas as tarefas em segundo plano sejam mescladas e executadas em segundo plano posteriormente:
|
||||||
|
|
||||||
|
```Python hl_lines="13 15 22 25"
|
||||||
|
{!../../../docs_src/background_tasks/tutorial002.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
Neste exemplo, as mensagens serão gravadas no arquivo `log.txt` _após_ o envio da resposta.
|
||||||
|
|
||||||
|
Se houver uma consulta na solicitação, ela será gravada no log em uma tarefa em segundo plano.
|
||||||
|
|
||||||
|
E então outra tarefa em segundo plano gerada na _função de operação de caminho_ escreverá uma mensagem usando o parâmetro de caminho `email`.
|
||||||
|
|
||||||
|
## Detalhes técnicos
|
||||||
|
|
||||||
|
A classe `BackgroundTasks` vem diretamente de <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>.
|
||||||
|
|
||||||
|
Ela é importada/incluída diretamente no FastAPI para que você possa importá-la do `fastapi` e evitar a importação acidental da alternativa `BackgroundTask` (sem o `s` no final) de `starlette.background`.
|
||||||
|
|
||||||
|
Usando apenas `BackgroundTasks` (e não `BackgroundTask`), é então possível usá-la como um parâmetro de _função de operação de caminho_ e deixar o **FastAPI** cuidar do resto para você, assim como ao usar o objeto `Request` diretamente.
|
||||||
|
|
||||||
|
Ainda é possível usar `BackgroundTask` sozinho no FastAPI, mas você deve criar o objeto em seu código e retornar uma Starlette `Response` incluindo-o.
|
||||||
|
|
||||||
|
Você pode ver mais detalhes na <a href="https://www.starlette.io/background/" class="external-link" target="_blank"> documentação oficiais da Starlette para tarefas em segundo plano </a>.
|
||||||
|
|
||||||
|
## Ressalva
|
||||||
|
|
||||||
|
Se você precisa realizar cálculos pesados em segundo plano e não necessariamente precisa que seja executado pelo mesmo processo (por exemplo, você não precisa compartilhar memória, variáveis, etc), você pode se beneficiar do uso de outras ferramentas maiores, como <a href="http://www.celeryproject.org/" class="external-link" target="_blank"> Celery </a>.
|
||||||
|
|
||||||
|
Eles tendem a exigir configurações mais complexas, um gerenciador de fila de mensagens/tarefas, como RabbitMQ ou Redis, mas permitem que você execute tarefas em segundo plano em vários processos e, especialmente, em vários servidores.
|
||||||
|
|
||||||
|
Para ver um exemplo, verifique os [Geradores de projeto](../project-generation.md){.internal-link target=\_blank}, todos incluem celery já configurado.
|
||||||
|
|
||||||
|
Mas se você precisa acessar variáveis e objetos do mesmo aplicativo **FastAPI**, ou precisa realizar pequenas tarefas em segundo plano (como enviar uma notificação por e-mail), você pode simplesmente usar `BackgroundTasks`.
|
||||||
|
|
||||||
|
## Recapitulando
|
||||||
|
|
||||||
|
Importe e use `BackgroundTasks` com parâmetros em _funções de operação de caminho_ e dependências para adicionar tarefas em segundo plano.
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
# Corpo da Requisição
|
||||||
|
|
||||||
|
Quando você precisa enviar dados de um cliente (como de um navegador web) para sua API, você o envia como um **corpo da requisição**.
|
||||||
|
|
||||||
|
O corpo da **requisição** é a informação enviada pelo cliente para sua API. O corpo da **resposta** é a informação que sua API envia para o cliente.
|
||||||
|
|
||||||
|
Sua API quase sempre irá enviar um corpo na **resposta**. Mas os clientes não necessariamente precisam enviar um corpo em toda **requisição**.
|
||||||
|
|
||||||
|
Para declarar um corpo da **requisição**, você utiliza os modelos do <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> com todos os seus poderes e benefícios.
|
||||||
|
|
||||||
|
!!! info "Informação"
|
||||||
|
Para enviar dados, você deve usar utilizar um dos métodos: `POST` (Mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||||
|
|
||||||
|
Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.
|
||||||
|
|
||||||
|
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição para um `GET`, e proxies que intermediarem podem não suportar o corpo da requisição.
|
||||||
|
|
||||||
|
## Importe o `BaseModel` do Pydantic
|
||||||
|
|
||||||
|
Primeiro, você precisa importar `BaseModel` do `pydantic`:
|
||||||
|
|
||||||
|
```Python hl_lines="4"
|
||||||
|
{!../../../docs_src/body/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Crie seu modelo de dados
|
||||||
|
|
||||||
|
Então você declara seu modelo de dados como uma classe que herda `BaseModel`.
|
||||||
|
|
||||||
|
Utilize os tipos Python padrão para todos os atributos:
|
||||||
|
|
||||||
|
```Python hl_lines="7-11"
|
||||||
|
{!../../../docs_src/body/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional.
|
||||||
|
|
||||||
|
Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"name": "Foo",
|
||||||
|
"description": "Uma descrição opcional",
|
||||||
|
"price": 45.2,
|
||||||
|
"tax": 3.5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
...como `description` e `tax` são opcionais (Com um valor padrão de `None`), esse JSON "`object`" também é válido:
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"name": "Foo",
|
||||||
|
"price": 45.2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Declare como um parâmetro
|
||||||
|
|
||||||
|
Para adicionar o corpo na *função de operação de rota*, declare-o da mesma maneira que você declarou parâmetros de rota e consulta:
|
||||||
|
|
||||||
|
```Python hl_lines="18"
|
||||||
|
{!../../../docs_src/body/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
...E declare o tipo como o modelo que você criou, `Item`.
|
||||||
|
|
||||||
|
## Resultados
|
||||||
|
|
||||||
|
Apenas com esse declaração de tipos do Python, o **FastAPI** irá:
|
||||||
|
|
||||||
|
* Ler o corpo da requisição como um JSON.
|
||||||
|
* Converter os tipos correspondentes (se necessário).
|
||||||
|
* Validar os dados.
|
||||||
|
* Se algum dados for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que está incorreto.
|
||||||
|
* Entregar a você a informação recebida no parâmetro `item`.
|
||||||
|
* Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (completação, etc) para todos os atributos e seus tipos.
|
||||||
|
* Gerar um <a href="https://json-schema.org" class="external-link" target="_blank">Esquema JSON</a> com as definições do seu modelo, você também pode utilizá-lo em qualquer lugar que quiser, se fizer sentido para seu projeto.
|
||||||
|
* Esses esquemas farão parte do esquema OpenAPI, e utilizados nas <abbr title="User Interfaces">UIs</abbr> de documentação automática.
|
||||||
|
|
||||||
|
## Documentação automática
|
||||||
|
|
||||||
|
Os esquemas JSON dos seus modelos farão parte do esquema OpenAPI gerado para sua aplicação, e aparecerão na documentação interativa da API:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/body/image01.png">
|
||||||
|
|
||||||
|
E também serão utilizados em cada *função de operação de rota* que utilizá-los:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/body/image02.png">
|
||||||
|
|
||||||
|
## Suporte do editor de texto:
|
||||||
|
|
||||||
|
No seu editor de texto, dentro da função você receberá dicas de tipos e completação em todo lugar (isso não aconteceria se você recebesse um `dict` em vez de um modelo Pydantic):
|
||||||
|
|
||||||
|
<img src="/img/tutorial/body/image03.png">
|
||||||
|
|
||||||
|
Você também poderá receber verificações de erros para operações de tipos incorretas:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/body/image04.png">
|
||||||
|
|
||||||
|
Isso não é por acaso, todo o framework foi construído em volta deste design.
|
||||||
|
|
||||||
|
E foi imensamente testado na fase de design, antes de qualquer implementação, para garantir que funcionaria para todos os editores de texto.
|
||||||
|
|
||||||
|
Houveram mudanças no próprio Pydantic para que isso fosse possível.
|
||||||
|
|
||||||
|
As capturas de tela anteriores foram capturas no <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
|
||||||
|
|
||||||
|
Mas você terá o mesmo suporte do editor no <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> e na maioria dos editores Python:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/body/image05.png">
|
||||||
|
|
||||||
|
!!! tip "Dica"
|
||||||
|
Se você utiliza o <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> como editor, você pode utilizar o <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Plugin do Pydantic para o PyCharm </a>.
|
||||||
|
|
||||||
|
Melhora o suporte do editor para seus modelos Pydantic com::
|
||||||
|
|
||||||
|
* completação automática
|
||||||
|
* verificação de tipos
|
||||||
|
* refatoração
|
||||||
|
* buscas
|
||||||
|
* inspeções
|
||||||
|
|
||||||
|
## Use o modelo
|
||||||
|
|
||||||
|
Dentro da função, você pode acessar todos os atributos do objeto do modelo diretamente:
|
||||||
|
|
||||||
|
```Python hl_lines="21"
|
||||||
|
{!../../../docs_src/body/tutorial002.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Corpo da requisição + parâmetros de rota
|
||||||
|
|
||||||
|
Você pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo.
|
||||||
|
|
||||||
|
O **FastAPI** irá reconhecer que os parâmetros da função que combinam com parâmetros de rota devem ser **retirados da rota**, e parâmetros da função que são declarados como modelos Pydantic sejam **retirados do corpo da requisição**.
|
||||||
|
|
||||||
|
```Python hl_lines="17-18"
|
||||||
|
{!../../../docs_src/body/tutorial003.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Corpo da requisição + parâmetros de rota + parâmetros de consulta
|
||||||
|
|
||||||
|
Você também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo.
|
||||||
|
|
||||||
|
O **FastAPI** irá reconhecer cada um deles e retirar a informação do local correto.
|
||||||
|
|
||||||
|
```Python hl_lines="18"
|
||||||
|
{!../../../docs_src/body/tutorial004.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
Os parâmetros da função serão reconhecidos conforme abaixo:
|
||||||
|
|
||||||
|
* Se o parâmetro também é declarado na **rota**, será utilizado como um parâmetro de rota.
|
||||||
|
* Se o parâmetro é de um **tipo único** (como `int`, `float`, `str`, `bool`, etc) será interpretado como um parâmetro de **consulta**.
|
||||||
|
* Se o parâmetro é declarado como um **modelo Pydantic**, será interpretado como o **corpo** da requisição.
|
||||||
|
|
||||||
|
!!! note "Observação"
|
||||||
|
O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`.
|
||||||
|
|
||||||
|
O `Union` em `Union[str, None]` não é utilizado pelo FastAPI, mas permite ao seu editor de texto lhe dar um suporte melhor e detectar erros.
|
||||||
|
|
||||||
|
## Sem o Pydantic
|
||||||
|
|
||||||
|
Se você não quer utilizar os modelos Pydantic, você também pode utilizar o parâmetro **Body**. Veja a documentação para [Body - Parâmetros múltiplos: Valores singulares no body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Parâmetros de Cookie
|
||||||
|
|
||||||
|
Você pode definir parâmetros de Cookie da mesma maneira que define paramêtros com `Query` e `Path`.
|
||||||
|
|
||||||
|
## Importe `Cookie`
|
||||||
|
|
||||||
|
Primeiro importe `Cookie`:
|
||||||
|
|
||||||
|
```Python hl_lines="3"
|
||||||
|
{!../../../docs_src/cookie_params/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Declare parâmetros de `Cookie`
|
||||||
|
|
||||||
|
Então declare os paramêtros de cookie usando a mesma estrutura que em `Path` e `Query`.
|
||||||
|
|
||||||
|
O primeiro valor é o valor padrão, você pode passar todas as validações adicionais ou parâmetros de anotação:
|
||||||
|
|
||||||
|
```Python hl_lines="9"
|
||||||
|
{!../../../docs_src/cookie_params/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note "Detalhes Técnicos"
|
||||||
|
`Cookie` é uma classe "irmã" de `Path` e `Query`. Ela também herda da mesma classe em comum `Param`.
|
||||||
|
|
||||||
|
Mas lembre-se que quando você importa `Query`, `Path`, `Cookie` e outras de `fastapi`, elas são na verdade funções que retornam classes especiais.
|
||||||
|
|
||||||
|
!!! info "Informação"
|
||||||
|
Para declarar cookies, você precisa usar `Cookie`, caso contrário, os parâmetros seriam interpretados como parâmetros de consulta.
|
||||||
|
|
||||||
|
## Recapitulando
|
||||||
|
|
||||||
|
Declare cookies com `Cookie`, usando o mesmo padrão comum que utiliza-se em `Query` e `Path`.
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Tipos de dados extras
|
||||||
|
|
||||||
|
Até agora, você tem usado tipos de dados comuns, tais como:
|
||||||
|
|
||||||
|
* `int`
|
||||||
|
* `float`
|
||||||
|
* `str`
|
||||||
|
* `bool`
|
||||||
|
|
||||||
|
Mas você também pode usar tipos de dados mais complexos.
|
||||||
|
|
||||||
|
E você ainda terá os mesmos recursos que viu até agora:
|
||||||
|
|
||||||
|
* Ótimo suporte do editor.
|
||||||
|
* Conversão de dados das requisições recebidas.
|
||||||
|
* Conversão de dados para os dados da resposta.
|
||||||
|
* Validação de dados.
|
||||||
|
* Anotação e documentação automáticas.
|
||||||
|
|
||||||
|
## Outros tipos de dados
|
||||||
|
|
||||||
|
Aqui estão alguns dos tipos de dados adicionais que você pode usar:
|
||||||
|
|
||||||
|
* `UUID`:
|
||||||
|
* Um "Identificador Universalmente Único" padrão, comumente usado como ID em muitos bancos de dados e sistemas.
|
||||||
|
* Em requisições e respostas será representado como uma `str`.
|
||||||
|
* `datetime.datetime`:
|
||||||
|
* O `datetime.datetime` do Python.
|
||||||
|
* Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `2008-09-15T15:53:00+05:00`.
|
||||||
|
* `datetime.date`:
|
||||||
|
* O `datetime.date` do Python.
|
||||||
|
* Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `2008-09-15`.
|
||||||
|
* `datetime.time`:
|
||||||
|
* O `datetime.time` do Python.
|
||||||
|
* Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `14:23:55.003`.
|
||||||
|
* `datetime.timedelta`:
|
||||||
|
* O `datetime.timedelta` do Python.
|
||||||
|
* Em requisições e respostas será representado como um `float` de segundos totais.
|
||||||
|
* O Pydantic também permite representá-lo como uma "codificação ISO 8601 diferença de tempo", <a href="https://pydantic-docs.helpmanual.io/#json-serialisation" class="external-link" target="_blank">cheque a documentação para mais informações</a>.
|
||||||
|
* `frozenset`:
|
||||||
|
* Em requisições e respostas, será tratado da mesma forma que um `set`:
|
||||||
|
* Nas requisições, uma lista será lida, eliminando duplicadas e convertendo-a em um `set`.
|
||||||
|
* Nas respostas, o `set` será convertido para uma `list`.
|
||||||
|
* O esquema gerado vai especificar que os valores do `set` são unicos (usando o `uniqueItems` do JSON Schema).
|
||||||
|
* `bytes`:
|
||||||
|
* O `bytes` padrão do Python.
|
||||||
|
* Em requisições e respostas será representado como uma `str`.
|
||||||
|
* O esquema gerado vai especificar que é uma `str` com o "formato" `binary`.
|
||||||
|
* `Decimal`:
|
||||||
|
* O `Decimal` padrão do Python.
|
||||||
|
* Em requisições e respostas será representado como um `float`.
|
||||||
|
* Você pode checar todos os tipos de dados válidos do Pydantic aqui: <a href="https://pydantic-docs.helpmanual.io/usage/types" class="external-link" target="_blank">Tipos de dados do Pydantic</a>.
|
||||||
|
|
||||||
|
## Exemplo
|
||||||
|
|
||||||
|
Aqui está um exemplo de *operação de rota* com parâmetros utilizando-se de alguns dos tipos acima.
|
||||||
|
|
||||||
|
```Python hl_lines="1 3 12-16"
|
||||||
|
{!../../../docs_src/extra_data_types/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note que os parâmetros dentro da função tem seu tipo de dados natural, e você pode, por exemplo, realizar manipulações normais de data, como:
|
||||||
|
|
||||||
|
```Python hl_lines="18-19"
|
||||||
|
{!../../../docs_src/extra_data_types/tutorial001.py!}
|
||||||
|
```
|
||||||
|
|
@ -72,7 +72,7 @@ O mesmo erro apareceria se você tivesse fornecido um `float` ao invés de um `i
|
||||||
|
|
||||||
## Documentação
|
## Documentação
|
||||||
|
|
||||||
Quando você abrir o seu navegador em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, você verá de forma automática e interativa a documtação da API como:
|
Quando você abrir o seu navegador em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, você verá de forma automática e interativa a documentação da API como:
|
||||||
|
|
||||||
<img src="/img/tutorial/path-params/image01.png">
|
<img src="/img/tutorial/path-params/image01.png">
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ Vamos utilizar essa aplicação como exemplo:
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial001.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
O parâmetro de consulta `q` é do tipo `Optional[str]`, o que significa que é do tipo `str` mas que também pode ser `None`, e de fato, o valor padrão é `None`, então o FastAPI saberá que não é obrigatório.
|
O parâmetro de consulta `q` é do tipo `Union[str, None]`, o que significa que é do tipo `str` mas que também pode ser `None`, e de fato, o valor padrão é `None`, então o FastAPI saberá que não é obrigatório.
|
||||||
|
|
||||||
!!! note "Observação"
|
!!! note "Observação"
|
||||||
O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`.
|
O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`.
|
||||||
|
|
||||||
O `Optional` em `Optional[str]` não é usado pelo FastAPI, mas permitirá que seu editor lhe dê um melhor suporte e detecte erros.
|
O `Union` em `Union[str, None]` não é usado pelo FastAPI, mas permitirá que seu editor lhe dê um melhor suporte e detecte erros.
|
||||||
|
|
||||||
## Validação adicional
|
## Validação adicional
|
||||||
|
|
||||||
|
|
@ -35,18 +35,18 @@ Agora utilize-o como valor padrão do seu parâmetro, definindo o parâmetro `ma
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note que substituímos o valor padrão de `None` para `Query(None)`, o primeiro parâmetro de `Query` serve para o mesmo propósito: definir o valor padrão do parâmetro.
|
Note que substituímos o valor padrão de `None` para `Query(default=None)`, o primeiro parâmetro de `Query` serve para o mesmo propósito: definir o valor padrão do parâmetro.
|
||||||
|
|
||||||
Então:
|
Então:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = Query(None)
|
q: Union[str, None] = Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
...Torna o parâmetro opcional, da mesma maneira que:
|
...Torna o parâmetro opcional, da mesma maneira que:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = None
|
q: Union[str, None] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
Mas o declara explicitamente como um parâmetro de consulta.
|
Mas o declara explicitamente como um parâmetro de consulta.
|
||||||
|
|
@ -61,17 +61,17 @@ Mas o declara explicitamente como um parâmetro de consulta.
|
||||||
Ou com:
|
Ou com:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
= Query(None)
|
= Query(default=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
E irá utilizar o `None` para detectar que o parâmetro de consulta não é obrigatório.
|
E irá utilizar o `None` para detectar que o parâmetro de consulta não é obrigatório.
|
||||||
|
|
||||||
O `Optional` é apenas para permitir que seu editor de texto lhe dê um melhor suporte.
|
O `Union` é apenas para permitir que seu editor de texto lhe dê um melhor suporte.
|
||||||
|
|
||||||
Então, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `max_length` que se aplica a textos:
|
Então, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `max_length` que se aplica a textos:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: str = Query(None, max_length=50)
|
q: str = Query(default=None, max_length=50)
|
||||||
```
|
```
|
||||||
|
|
||||||
Isso irá validar os dados, mostrar um erro claro quando os dados forem inválidos, e documentar o parâmetro na *operação de rota* do esquema OpenAPI..
|
Isso irá validar os dados, mostrar um erro claro quando os dados forem inválidos, e documentar o parâmetro na *operação de rota* do esquema OpenAPI..
|
||||||
|
|
@ -80,7 +80,7 @@ Isso irá validar os dados, mostrar um erro claro quando os dados forem inválid
|
||||||
|
|
||||||
Você também pode incluir um parâmetro `min_length`:
|
Você também pode incluir um parâmetro `min_length`:
|
||||||
|
|
||||||
```Python hl_lines="9"
|
```Python hl_lines="10"
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial003.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial003.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -88,7 +88,7 @@ Você também pode incluir um parâmetro `min_length`:
|
||||||
|
|
||||||
Você pode definir uma <abbr title="Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um parâmetro de busca para textos.">expressão regular</abbr> que combine com um padrão esperado pelo parâmetro:
|
Você pode definir uma <abbr title="Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um parâmetro de busca para textos.">expressão regular</abbr> que combine com um padrão esperado pelo parâmetro:
|
||||||
|
|
||||||
```Python hl_lines="10"
|
```Python hl_lines="11"
|
||||||
{!../../../docs_src/query_params_str_validations/tutorial004.py!}
|
{!../../../docs_src/query_params_str_validations/tutorial004.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -126,13 +126,13 @@ q: str
|
||||||
em vez desta:
|
em vez desta:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = None
|
q: Union[str, None] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
Mas agora nós o estamos declarando como `Query`, conforme abaixo:
|
Mas agora nós o estamos declarando como `Query`, conforme abaixo:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
q: Optional[str] = Query(None, min_length=3)
|
q: Union[str, None] = Query(default=None, min_length=3)
|
||||||
```
|
```
|
||||||
|
|
||||||
Então, quando você precisa declarar um parâmetro obrigatório utilizando o `Query`, você pode utilizar `...` como o primeiro argumento:
|
Então, quando você precisa declarar um parâmetro obrigatório utilizando o `Query`, você pode utilizar `...` como o primeiro argumento:
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
@ -60,8 +62,11 @@ nav:
|
||||||
- tutorial/index.md
|
- tutorial/index.md
|
||||||
- tutorial/first-steps.md
|
- tutorial/first-steps.md
|
||||||
- tutorial/path-params.md
|
- tutorial/path-params.md
|
||||||
|
- tutorial/body.md
|
||||||
- tutorial/body-fields.md
|
- tutorial/body-fields.md
|
||||||
|
- tutorial/extra-data-types.md
|
||||||
- tutorial/query-params-str-validations.md
|
- tutorial/query-params-str-validations.md
|
||||||
|
- tutorial/cookie-params.md
|
||||||
- Segurança:
|
- Segurança:
|
||||||
- tutorial/security/index.md
|
- tutorial/security/index.md
|
||||||
- Guia de Usuário Avançado:
|
- Guia de Usuário Avançado:
|
||||||
|
|
@ -70,10 +75,12 @@ nav:
|
||||||
- deployment/index.md
|
- deployment/index.md
|
||||||
- deployment/versions.md
|
- deployment/versions.md
|
||||||
- deployment/https.md
|
- deployment/https.md
|
||||||
|
- deployment/deta.md
|
||||||
- alternatives.md
|
- alternatives.md
|
||||||
- history-design-future.md
|
- history-design-future.md
|
||||||
- external-links.md
|
- external-links.md
|
||||||
- benchmarks.md
|
- benchmarks.md
|
||||||
|
- help-fastapi.md
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- toc:
|
- toc:
|
||||||
permalink: true
|
permalink: true
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,505 @@
|
||||||
|
# Конкурентность и async / await
|
||||||
|
|
||||||
|
Здесь приведена подробная информация об использовании синтаксиса `async def` при написании *функций обработки пути*, а также рассмотрены основы асинхронного программирования, конкурентности и параллелизма.
|
||||||
|
|
||||||
|
## Нет времени?<a name="in-a-hurry"></a>
|
||||||
|
|
||||||
|
<abbr title="too long; didn't read (основная мысль)"><strong>TL;DR:</strong></abbr>
|
||||||
|
|
||||||
|
Допустим, вы используете сторонюю библиотеку, которая требует вызова с ключевым словом `await`:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
results = await some_library()
|
||||||
|
```
|
||||||
|
|
||||||
|
В этом случае *функции обработки пути* необходимо объявлять с использованием синтаксиса `async def`:
|
||||||
|
|
||||||
|
```Python hl_lines="2"
|
||||||
|
@app.get('/')
|
||||||
|
async def read_results():
|
||||||
|
results = await some_library()
|
||||||
|
return results
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
`await` можно использовать только внутри функций, объявленных с использованием `async def`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Если вы обращаетесь к сторонней библиотеке, которая с чем-то взаимодействует
|
||||||
|
(с базой данных, API, файловой системой и т. д.), и не имеет поддержки синтаксиса `await`
|
||||||
|
(что относится сейчас к большинству библиотек для работы с базами данных), то
|
||||||
|
объявляйте *функции обработки пути* обычным образом с помощью `def`, например:
|
||||||
|
|
||||||
|
```Python hl_lines="2"
|
||||||
|
@app.get('/')
|
||||||
|
def results():
|
||||||
|
results = some_library()
|
||||||
|
return results
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Если вашему приложению (странным образом) не нужно ни с чем взаимодействовать и, соответственно,
|
||||||
|
ожидать ответа, используйте `async def`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Если вы не уверены, используйте обычный синтаксис `def`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Примечание**: при необходимости можно смешивать `def` и `async def` в *функциях обработки пути*
|
||||||
|
и использовать в каждом случае наиболее подходящий синтаксис. А FastAPI сделает с этим всё, что нужно.
|
||||||
|
|
||||||
|
В любом из описанных случаев FastAPI работает асинхронно и очень быстро.
|
||||||
|
|
||||||
|
Однако придерживаясь указанных советов, можно получить дополнительную оптимизацию производительности.
|
||||||
|
|
||||||
|
## Технические подробности
|
||||||
|
|
||||||
|
Современные версии Python поддерживают разработку так называемого **"асинхронного кода"** посредством написания **"сопрограмм"** с использованием синтаксиса **`async` и `await`**.
|
||||||
|
|
||||||
|
Ниже разберём эту фразу по частям:
|
||||||
|
|
||||||
|
* **Асинхронный код**
|
||||||
|
* **`async` и `await`**
|
||||||
|
* **Сопрограммы**
|
||||||
|
|
||||||
|
## Асинхронный код
|
||||||
|
|
||||||
|
Асинхронный код означает, что в языке 💬 есть возможность сообщить машине / программе 🤖,
|
||||||
|
что в определённой точке кода ей 🤖 нужно будет ожидать завершения выполнения *чего-то ещё* в другом месте. Допустим это *что-то ещё* называется "медленный файл" 📝.
|
||||||
|
|
||||||
|
И пока мы ждём завершения работы с "медленным файлом" 📝, компьютер может переключиться для выполнения других задач.
|
||||||
|
|
||||||
|
Но при каждой возможности компьютер / программа 🤖 будет возвращаться обратно. Например, если он 🤖 опять окажется в режиме ожидания, или когда закончит всю работу. В этом случае компьютер 🤖 проверяет, не завершена ли какая-нибудь из текущих задач.
|
||||||
|
|
||||||
|
Потом он 🤖 берёт первую выполненную задачу (допустим, наш "медленный файл" 📝) и продолжает работу, производя с ней необходимые действия.
|
||||||
|
|
||||||
|
Вышеупомянутое "что-то ещё", завершения которого приходится ожидать, обычно относится к достаточно "медленным" операциям <abbr title="Ввода-вывода">I/O</abbr> (по сравнению со скоростью работы процессора и оперативной памяти), например:
|
||||||
|
|
||||||
|
* отправка данных от клиента по сети
|
||||||
|
* получение клиентом данных, отправленных вашей программой по сети
|
||||||
|
* чтение системой содержимого файла с диска и передача этих данных программе
|
||||||
|
* запись на диск данных, которые программа передала системе
|
||||||
|
* обращение к удалённому API
|
||||||
|
* ожидание завершения операции с базой данных
|
||||||
|
* получение результатов запроса к базе данных
|
||||||
|
* и т. д.
|
||||||
|
|
||||||
|
Поскольку в основном время тратится на ожидание выполнения операций <abbr title="Ввода-вывода">I/O</abbr>,
|
||||||
|
их обычно называют операциями, <abbr title="I/O bound">ограниченными скоростью ввода-вывода</abbr>.
|
||||||
|
|
||||||
|
Код называют "асинхронным", потому что компьютеру / программе не требуется "синхронизироваться" с медленной задачей и,
|
||||||
|
будучи в простое, ожидать момента её завершения, с тем чтобы забрать результат и продолжить работу.
|
||||||
|
|
||||||
|
Вместо этого в "асинхронной" системе завершённая задача может немного подождать (буквально несколько микросекунд),
|
||||||
|
пока компьютер / программа занимается другими важными вещами, с тем чтобы потом вернуться,
|
||||||
|
забрать результаты выполнения и начать их обрабатывать.
|
||||||
|
|
||||||
|
"Синхронное" исполнение (в противовес "асинхронному") также называют <abbr title="sequential">"последовательным"</abbr>,
|
||||||
|
потому что компьютер / программа последовательно выполняет все требуемые шаги перед тем, как перейти к следующей задаче,
|
||||||
|
даже если в процессе приходится ждать.
|
||||||
|
|
||||||
|
### Конкурентность и бургеры
|
||||||
|
|
||||||
|
Тот **асинхронный** код, о котором идёт речь выше, иногда называют **"конкурентностью"**. Она отличается от **"параллелизма"**.
|
||||||
|
|
||||||
|
Да, **конкурентность** и **параллелизм** подразумевают, что разные вещи происходят примерно в одно время.
|
||||||
|
|
||||||
|
Но внутреннее устройство **конкурентности** и **параллелизма** довольно разное.
|
||||||
|
|
||||||
|
Чтобы это понять, представьте такую картину:
|
||||||
|
|
||||||
|
### Конкурентные бургеры
|
||||||
|
|
||||||
|
<!-- The gender neutral cook emoji "🧑🍳" does not render well in browsers. In the meantime, I'm using a mix of male "👨🍳" and female "👩🍳" cooks. -->
|
||||||
|
|
||||||
|
Вы идёте со своей возлюбленной 😍 в фастфуд 🍔 и становитесь в очередь, в это время кассир 💁 принимает заказы у посетителей перед вами.
|
||||||
|
|
||||||
|
Когда наконец подходит очередь, вы заказываете парочку самых вкусных и навороченных бургеров 🍔, один для своей возлюбленной 😍, а другой себе.
|
||||||
|
|
||||||
|
Отдаёте деньги 💸.
|
||||||
|
|
||||||
|
Кассир 💁 что-то говорит поварам на кухне 👨🍳, теперь они знают, какие бургеры нужно будет приготовить 🍔
|
||||||
|
(но пока они заняты бургерами предыдущих клиентов).
|
||||||
|
|
||||||
|
Кассир 💁 отдаёт вам чек с номером заказа.
|
||||||
|
|
||||||
|
В ожидании еды вы идёте со своей возлюбленной 😍 выбрать столик, садитесь и довольно продолжительное время общаетесь 😍
|
||||||
|
(поскольку ваши бургеры самые навороченные, готовятся они не так быстро ✨🍔✨).
|
||||||
|
|
||||||
|
Сидя за столиком с возлюбленной 😍 в ожидании бургеров 🍔, вы отлично проводите время,
|
||||||
|
восхищаясь её великолепием, красотой и умом ✨😍✨.
|
||||||
|
|
||||||
|
Всё ещё ожидая заказ и болтая со своей возлюбленной 😍, время от времени вы проверяете,
|
||||||
|
какой номер горит над прилавком, и не подошла ли уже ваша очередь.
|
||||||
|
|
||||||
|
И вот наконец настаёт этот момент, и вы идёте к стойке, чтобы забрать бургеры 🍔 и вернуться за столик.
|
||||||
|
|
||||||
|
Вы со своей возлюбленной 😍 едите бургеры 🍔 и отлично проводите время ✨.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
А теперь представьте, что в этой небольшой истории вы компьютер / программа 🤖.
|
||||||
|
|
||||||
|
В очереди вы просто глазеете по сторонам 😴, ждёте и ничего особо "продуктивного" не делаете.
|
||||||
|
Но очередь движется довольно быстро, поскольку кассир 💁 только принимает заказы (а не занимается приготовлением еды), так что ничего страшного.
|
||||||
|
|
||||||
|
Когда подходит очередь вы наконец предпринимаете "продуктивные" действия 🤓: просматриваете меню, выбираете в нём что-то, узнаёте, что хочет ваша возлюбленная 😍, собираетесь оплатить 💸, смотрите, какую достали карту, проверяете, чтобы с вас списали верную сумму, и что в заказе всё верно и т. д.
|
||||||
|
|
||||||
|
И хотя вы всё ещё не получили бургеры 🍔, ваша работа с кассиром 💁 ставится "на паузу" ⏸,
|
||||||
|
поскольку теперь нужно ждать 🕙, когда заказ приготовят.
|
||||||
|
|
||||||
|
Но отойдя с номерком от прилавка, вы садитесь за столик и можете переключить 🔀 внимание
|
||||||
|
на свою возлюбленную 😍 и "работать" ⏯ 🤓 уже над этим. И вот вы снова очень
|
||||||
|
"продуктивны" 🤓, мило болтаете вдвоём и всё такое 😍.
|
||||||
|
|
||||||
|
В какой-то момент кассир 💁 поместит на табло ваш номер, подразумевая, что бургеры готовы 🍔, но вы не станете подскакивать как умалишённый, лишь только увидев на экране свою очередь. Вы уверены, что ваши бургеры 🍔 никто не утащит, ведь у вас свой номерок, а у других свой.
|
||||||
|
|
||||||
|
Поэтому вы подождёте, пока возлюбленная 😍 закончит рассказывать историю (закончите текущую работу ⏯ / задачу в обработке 🤓),
|
||||||
|
и мило улыбнувшись, скажете, что идёте забирать заказ ⏸.
|
||||||
|
|
||||||
|
И вот вы подходите к стойке 🔀, к первоначальной задаче, которая уже завершена ⏯, берёте бургеры 🍔, говорите спасибо и относите заказ за столик. На этом заканчивается этап / задача взаимодействия с кассой ⏹.
|
||||||
|
В свою очередь порождается задача "поедание бургеров" 🔀 ⏯, но предыдущая ("получение бургеров") завершена ⏹.
|
||||||
|
|
||||||
|
### Параллельные бургеры
|
||||||
|
|
||||||
|
Теперь представим, что вместо бургерной "Конкурентные бургеры" вы решили сходить в "Параллельные бургеры".
|
||||||
|
|
||||||
|
И вот вы идёте со своей возлюбленной 😍 отведать параллельного фастфуда 🍔.
|
||||||
|
|
||||||
|
Вы становитесь в очередь пока несколько (пусть будет 8) кассиров, которые по совместительству ещё и повары 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳, принимают заказы у посетителей перед вами.
|
||||||
|
|
||||||
|
При этом клиенты не отходят от стойки и ждут 🕙 получения еды, поскольку каждый
|
||||||
|
из 8 кассиров идёт на кухню готовить бургеры 🍔, а только потом принимает следующий заказ.
|
||||||
|
|
||||||
|
Наконец настаёт ваша очередь, и вы просите два самых навороченных бургера 🍔, один для дамы сердца 😍, а другой себе.
|
||||||
|
|
||||||
|
Ни о чём не жалея, расплачиваетесь 💸.
|
||||||
|
|
||||||
|
И кассир уходит на кухню 👨🍳.
|
||||||
|
|
||||||
|
Вам приходится ждать перед стойкой 🕙, чтобы никто по случайности не забрал ваши бургеры 🍔, ведь никаких номерков у вас нет.
|
||||||
|
|
||||||
|
Поскольку вы с возлюбленной 😍 хотите получить заказ вовремя 🕙, и следите за тем, чтобы никто не вклинился в очередь,
|
||||||
|
у вас не получается уделять должного внимание своей даме сердца 😞.
|
||||||
|
|
||||||
|
Это "синхронная" работа, вы "синхронизированы" с кассиром/поваром 👨🍳. Приходится ждать 🕙 у стойки,
|
||||||
|
когда кассир/повар 👨🍳 закончит делать бургеры 🍔 и вручит вам заказ, иначе его случайно может забрать кто-то другой.
|
||||||
|
|
||||||
|
Наконец кассир/повар 👨🍳 возвращается с бургерами 🍔 после невыносимо долгого ожидания 🕙 за стойкой.
|
||||||
|
|
||||||
|
Вы скорее забираете заказ 🍔 и идёте с возлюбленной 😍 за столик.
|
||||||
|
|
||||||
|
Там вы просто едите эти бургеры, и на этом всё 🍔 ⏹.
|
||||||
|
|
||||||
|
Вам не особо удалось пообщаться, потому что большую часть времени 🕙 пришлось провести у кассы 😞.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
В описанном сценарии вы компьютер / программа 🤖 с двумя исполнителями (вы и ваша возлюбленная 😍),
|
||||||
|
на протяжении долгого времени 🕙 вы оба уделяете всё внимание ⏯ задаче "ждать на кассе".
|
||||||
|
|
||||||
|
В этом ресторане быстрого питания 8 исполнителей (кассиров/поваров) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳.
|
||||||
|
Хотя в бургерной конкурентного типа было всего два (один кассир и один повар) 💁 👨🍳.
|
||||||
|
|
||||||
|
Несмотря на обилие работников, опыт в итоге получился не из лучших 😞.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Так бы выглядел аналог истории про бургерную 🍔 в "параллельном" мире.
|
||||||
|
|
||||||
|
Вот более реалистичный пример. Представьте себе банк.
|
||||||
|
|
||||||
|
До недавних пор в большинстве банков было несколько кассиров 👨💼👨💼👨💼👨💼 и длинные очереди 🕙🕙🕙🕙🕙🕙🕙🕙.
|
||||||
|
|
||||||
|
Каждый кассир обслуживал одного клиента, потом следующего 👨💼⏯.
|
||||||
|
|
||||||
|
Нужно было долгое время 🕙 стоять перед окошком вместе со всеми, иначе пропустишь свою очередь.
|
||||||
|
|
||||||
|
Сомневаюсь, что у вас бы возникло желание прийти с возлюбленной 😍 в банк 🏦 оплачивать налоги.
|
||||||
|
|
||||||
|
### Выводы о бургерах
|
||||||
|
|
||||||
|
В нашей истории про поход в фастфуд за бургерами приходится много ждать 🕙,
|
||||||
|
поэтому имеет смысл организовать конкурентную систему ⏸🔀⏯.
|
||||||
|
|
||||||
|
И то же самое с большинством веб-приложений.
|
||||||
|
|
||||||
|
Пользователей очень много, но ваш сервер всё равно вынужден ждать 🕙 запросы по их слабому интернет-соединению.
|
||||||
|
|
||||||
|
Потом снова ждать 🕙, пока вернётся ответ.
|
||||||
|
|
||||||
|
<!--https://forum.wordreference.com/threads/%D0%9D%D0%BE-%D0%B5%D1%81%D0%BB%D0%B8.3258695/-->
|
||||||
|
Это ожидание 🕙 измеряется микросекундами, но если всё сложить, то набегает довольно много времени.
|
||||||
|
|
||||||
|
Вот почему есть смысл использовать асинхронное ⏸🔀⏯ программирование при построении веб-API.
|
||||||
|
|
||||||
|
Большинство популярных фреймворков (включая Flask и Django) создавались
|
||||||
|
до появления в Python новых возможностей асинхронного программирования. Поэтому
|
||||||
|
их можно разворачивать с поддержкой параллельного исполнения или асинхронного
|
||||||
|
программирования старого типа, которое не настолько эффективно.
|
||||||
|
|
||||||
|
При том, что основная спецификация асинхронного взаимодействия Python с веб-сервером
|
||||||
|
(<a href="https://asgi.readthedocs.io" class="external-link" target="_blank">ASGI</a>)
|
||||||
|
была разработана командой Django для внедрения поддержки веб-сокетов.
|
||||||
|
|
||||||
|
Именно асинхронность сделала NodeJS таким популярным (несмотря на то, что он не параллельный),
|
||||||
|
и в этом преимущество Go как языка программирования.
|
||||||
|
|
||||||
|
И тот же уровень производительности даёт **FastAPI**.
|
||||||
|
|
||||||
|
Поскольку можно использовать преимущества параллелизма и асинхронности вместе,
|
||||||
|
вы получаете производительность лучше, чем у большинства протестированных NodeJS фреймворков
|
||||||
|
и на уровне с Go, который является компилируемым языком близким к C <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="Центральный процессор (CPU)">ЦП</abbr>,
|
||||||
|
такие задачи называют <abbr title="CPU bound">ограниченными производительностью процессора</abbr>.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Ограничение по процессору проявляется в операциях, где требуется выполнять сложные математические вычисления.
|
||||||
|
|
||||||
|
Например:
|
||||||
|
|
||||||
|
* Обработка **звука** или **изображений**.
|
||||||
|
* **Компьютерное зрение**: изображение состоит из миллионов пикселей, в каждом пикселе 3 составляющих цвета,
|
||||||
|
обработка обычно требует проведения расчётов по всем пикселям сразу.
|
||||||
|
* **Машинное обучение**: здесь обычно требуется умножение "матриц" и "векторов".
|
||||||
|
Представьте гигантскую таблицу с числами в Экселе, и все их надо одновременно перемножить.
|
||||||
|
* **Глубокое обучение**: это область *машинного обучения*, поэтому сюда подходит то же описание.
|
||||||
|
Просто у вас будет не одна таблица в Экселе, а множество. В ряде случаев используется
|
||||||
|
специальный процессор для создания и / или использования построенных таким образом моделей.
|
||||||
|
|
||||||
|
### Конкурентность + параллелизм: Веб + машинное обучение
|
||||||
|
|
||||||
|
**FastAPI** предоставляет возможности конкуретного программирования,
|
||||||
|
которое очень распространено в веб-разработке (именно этим славится NodeJS).
|
||||||
|
|
||||||
|
Кроме того вы сможете использовать все преимущества параллелизма и
|
||||||
|
<abbr title="multiprocessing">многопроцессорности</abbr> (когда несколько процессов работают параллельно),
|
||||||
|
если рабочая нагрузка предполагает **ограничение по процессору**,
|
||||||
|
как, например, в системах машинного обучения. <!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_329-->
|
||||||
|
|
||||||
|
Необходимо также отметить, что Python является главным языком в области
|
||||||
|
<abbr title="наука о данных (data science)">**дата-сайенс**</abbr>,
|
||||||
|
машинного обучения и, особенно, глубокого обучения. Всё это делает FastAPI
|
||||||
|
отличным вариантом (среди многих других) для разработки веб-API и приложений
|
||||||
|
в области дата-сайенс / машинного обучения.
|
||||||
|
|
||||||
|
Как добиться такого параллелизма в эксплуатации описано в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}.
|
||||||
|
|
||||||
|
## `async` и `await`
|
||||||
|
|
||||||
|
В современных версиях Python разработка асинхронного кода реализована очень интуитивно.
|
||||||
|
Он выглядит как обычный "последовательный" код и самостоятельно выполняет "ожидание", когда это необходимо.
|
||||||
|
|
||||||
|
Если некая операция требует ожидания перед тем, как вернуть результат, и
|
||||||
|
поддерживает современные возможности Python, код можно написать следующим образом:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
burgers = await get_burgers(2)
|
||||||
|
```
|
||||||
|
|
||||||
|
Главное здесь слово `await`. Оно сообщает интерпретатору, что необходимо дождаться ⏸
|
||||||
|
пока `get_burgers(2)` закончит свои дела 🕙, и только после этого сохранить результат в `burgers`.
|
||||||
|
Зная это, Python может пока переключиться на выполнение других задач 🔀 ⏯
|
||||||
|
(например получение следующего запроса).<!--http://new.gramota.ru/spravka/buro/search-answer?s=296614-->
|
||||||
|
|
||||||
|
Чтобы ключевое слово `await` сработало, оно должно находиться внутри функции,
|
||||||
|
которая поддерживает асинхронность. Для этого вам просто нужно объявить её как `async def`:
|
||||||
|
|
||||||
|
```Python hl_lines="1"
|
||||||
|
async def get_burgers(number: int):
|
||||||
|
# Готовим бургеры по специальному асинхронному рецепту
|
||||||
|
return burgers
|
||||||
|
```
|
||||||
|
|
||||||
|
...вместо `def`:
|
||||||
|
|
||||||
|
```Python hl_lines="2"
|
||||||
|
# Это не асинхронный код
|
||||||
|
def get_sequential_burgers(number: int):
|
||||||
|
# Готовим бургеры последовательно по шагам
|
||||||
|
return burgers
|
||||||
|
```
|
||||||
|
|
||||||
|
Объявление `async def` указывает интерпретатору, что внутри этой функции
|
||||||
|
следует ожидать выражений `await`, и что можно поставить выполнение такой функции на "паузу" ⏸ и
|
||||||
|
переключиться на другие задачи 🔀, с тем чтобы вернуться сюда позже.
|
||||||
|
|
||||||
|
Если вы хотите вызвать функцию с `async def`, вам нужно <abbr title="await">"ожидать"</abbr> её.
|
||||||
|
Поэтому такое не сработает:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
# Это не заработает, поскольку get_burgers объявлена с использованием async def
|
||||||
|
burgers = get_burgers(2)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Если сторонняя библиотека требует вызывать её с ключевым словом `await`,
|
||||||
|
необходимо писать *функции обработки пути* с использованием `async def`, например:
|
||||||
|
|
||||||
|
```Python hl_lines="2-3"
|
||||||
|
@app.get('/burgers')
|
||||||
|
async def read_burgers():
|
||||||
|
burgers = await get_burgers(2)
|
||||||
|
return burgers
|
||||||
|
```
|
||||||
|
|
||||||
|
### Технические подробности
|
||||||
|
|
||||||
|
Как вы могли заметить, `await` может применяться только в функциях, объявленных с использованием `async def`.
|
||||||
|
|
||||||
|
<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_128-->
|
||||||
|
Но выполнение такой функции необходимо "ожидать" с помощью `await`.
|
||||||
|
Это означает, что её можно вызвать только из другой функции, которая тоже объявлена с `async def`.
|
||||||
|
|
||||||
|
Но как же тогда появилась первая <abbr title="или яйцо?🤔">курица</abbr>? В смысле... как нам вызвать первую асинхронную функцию?
|
||||||
|
|
||||||
|
При работе с **FastAPI** просто не думайте об этом, потому что "первой" функцией является ваша *функция обработки пути*,
|
||||||
|
и дальше с этим разберётся FastAPI.
|
||||||
|
|
||||||
|
Кроме того, если хотите, вы можете использовать синтаксис `async` / `await` и без FastAPI.
|
||||||
|
|
||||||
|
### Пишите свой асинхронный код
|
||||||
|
|
||||||
|
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> в Python, так и с <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.<!--http://new.gramota.ru/spravka/buro/search-answer?s=285295-->
|
||||||
|
|
||||||
|
В частности, вы можете напрямую использовать <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>, чтобы они были максимально совместимыми и получали его преимущества (например *структурную конкурентность*).
|
||||||
|
|
||||||
|
### Другие виды асинхронного программирования
|
||||||
|
|
||||||
|
Стиль написания кода с `async` и `await` появился в языке Python относительно недавно.
|
||||||
|
|
||||||
|
Но он сильно облегчает работу с асинхронным кодом.
|
||||||
|
|
||||||
|
Ровно такой же синтаксис (ну или почти такой же) недавно был включён в современные версии JavaScript (в браузере и NodeJS).
|
||||||
|
|
||||||
|
До этого поддержка асинхронного кода была реализована намного сложнее, и его было труднее воспринимать.
|
||||||
|
|
||||||
|
В предыдущих версиях Python для этого использовались потоки или <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. Но такой код намного сложнее понимать, отлаживать и мысленно представлять.
|
||||||
|
|
||||||
|
Что касается JavaScript (в браузере и NodeJS), раньше там использовали для этой цели
|
||||||
|
<abbr title="callback">"обратные вызовы"</abbr>. Что выливалось в
|
||||||
|
<a href="http://callbackhell.ru/" class="external-link" target="_blank">ад обратных вызовов</a>.
|
||||||
|
|
||||||
|
## Сопрограммы
|
||||||
|
|
||||||
|
<abbr title="coroutine">**Корути́на**</abbr> (или же сопрограмма) — это крутое словечко для именования той сущности,
|
||||||
|
которую возвращает функция `async def`. Python знает, что её можно запустить, как и обычную функцию,
|
||||||
|
но кроме того сопрограмму можно поставить на паузу ⏸ в том месте, где встретится слово `await`.
|
||||||
|
|
||||||
|
Всю функциональность асинхронного программирования с использованием `async` и `await`
|
||||||
|
часто обобщают словом "корутины". Они аналогичны <abbr title="Goroutines">"горутинам"</abbr>, ключевой особенности
|
||||||
|
языка Go.
|
||||||
|
|
||||||
|
## Заключение
|
||||||
|
|
||||||
|
В самом начале была такая фраза:
|
||||||
|
|
||||||
|
> Современные версии Python поддерживают разработку так называемого
|
||||||
|
**"асинхронного кода"** посредством написания **"сопрограмм"** с использованием
|
||||||
|
синтаксиса **`async` и `await`**.
|
||||||
|
|
||||||
|
Теперь всё должно звучать понятнее. ✨
|
||||||
|
|
||||||
|
На этом основана работа FastAPI (посредством Starlette), и именно это
|
||||||
|
обеспечивает его высокую производительность.
|
||||||
|
|
||||||
|
## Очень технические подробности
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
Этот раздел читать не обязательно.
|
||||||
|
|
||||||
|
Здесь приводятся подробности внутреннего устройства **FastAPI**.
|
||||||
|
|
||||||
|
Но если вы обладаете техническими знаниями (корутины, потоки, блокировка и т. д.)
|
||||||
|
и вам интересно, как FastAPI обрабатывает `async def` в отличие от обычных `def`,
|
||||||
|
читайте дальше.
|
||||||
|
|
||||||
|
### Функции обработки пути
|
||||||
|
|
||||||
|
Когда вы объявляете *функцию обработки пути* обычным образом с ключевым словом `def`
|
||||||
|
вместо `async def`, FastAPI ожидает её выполнения, запустив функцию во внешнем
|
||||||
|
<abbr title="threadpool">пуле потоков</abbr>, а не напрямую (это бы заблокировало сервер).
|
||||||
|
|
||||||
|
Если ранее вы использовали другой асинхронный фреймворк, который работает иначе,
|
||||||
|
и привыкли объявлять простые вычислительные *функции* через `def` ради
|
||||||
|
незначительного прироста скорости (порядка 100 наносекунд), обратите внимание,
|
||||||
|
что с **FastAPI** вы получите противоположный эффект. В таком случае больше подходит
|
||||||
|
`async def`, если только *функция обработки пути* не использует код, приводящий
|
||||||
|
к блокировке <abbr title="Ввод/вывод: чтение и запись на диск, сетевые соединения.">I/O</abbr>.
|
||||||
|
<!--Уточнить: Не использовать async def, если код приводит к блокировке IO?-->
|
||||||
|
|
||||||
|
<!--http://new.gramota.ru/spravka/punctum?layout=item&id=58_285-->
|
||||||
|
Но в любом случае велика вероятность, что **FastAPI** [окажется быстрее](/#performance){.internal-link target=_blank}
|
||||||
|
другого фреймворка (или хотя бы на уровне с ним).
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
|
||||||
|
То же относится к зависимостям. Если это обычная функция `def`, а не `async def`,
|
||||||
|
она запускается во внешнем пуле потоков.
|
||||||
|
|
||||||
|
### Подзависимости
|
||||||
|
|
||||||
|
Вы можете объявить множество ссылающихся друг на друга зависимостей и подзависимостей
|
||||||
|
(в виде параметров при определении функции). Какие-то будут созданы с помощью `async def`,
|
||||||
|
другие обычным образом через `def`, и такая схема вполне работоспособна. Функции,
|
||||||
|
объявленные с помощью `def` будут запускаться на внешнем потоке (из пула),
|
||||||
|
а не с помощью `await`.
|
||||||
|
|
||||||
|
### Другие служебные функции
|
||||||
|
|
||||||
|
Любые другие служебные функции, которые вы вызываете напрямую, можно объявлять
|
||||||
|
с использованием `def` или `async def`. FastAPI не будет влиять на то, как вы
|
||||||
|
их запускаете.
|
||||||
|
|
||||||
|
Этим они отличаются от функций, которые FastAPI вызывает самостоятельно:
|
||||||
|
*функции обработки пути* и зависимости.
|
||||||
|
|
||||||
|
Если служебная функция объявлена с помощью `def`, она будет вызвана напрямую
|
||||||
|
(как вы и написали в коде), а не в отдельном потоке. Если же она объявлена с
|
||||||
|
помощью `async def`, её вызов должен осуществляться с ожиданием через `await`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--http://new.gramota.ru/spravka/buro/search-answer?s=299749-->
|
||||||
|
Ещё раз повторим, что все эти технические подробности полезны, только если вы специально их искали.
|
||||||
|
|
||||||
|
В противном случае просто ознакомьтесь с основными принципами в разделе выше: <a href="#in-a-hurry">Нет времени?</a>.
|
||||||
|
|
@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -275,7 +275,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -284,7 +284,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -447,7 +447,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
@ -54,6 +56,7 @@ nav:
|
||||||
- tr: /tr/
|
- tr: /tr/
|
||||||
- uk: /uk/
|
- uk: /uk/
|
||||||
- zh: /zh/
|
- zh: /zh/
|
||||||
|
- async.md
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- toc:
|
- toc:
|
||||||
permalink: true
|
permalink: true
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -275,7 +275,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -284,7 +284,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -447,7 +447,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiy
|
||||||
* Kullandığın geliştirme araçları ile iyi çalışır **<abbr title="Integrated Development Environment, kod editörüne benzer">IDE</abbr>/<abbr title="Code errorlarınızı inceleyen program">linter</abbr>/brain**:
|
* Kullandığın geliştirme araçları ile iyi çalışır **<abbr title="Integrated Development Environment, kod editörüne benzer">IDE</abbr>/<abbr title="Code errorlarınızı inceleyen program">linter</abbr>/brain**:
|
||||||
* Pydantic'in veri yapıları aslında sadece senin tanımladığın classlar; Bu yüzden doğrulanmış dataların ile otomatik tamamlama, linting ve mypy'ı kullanarak sorunsuz bir şekilde çalışabilirsin
|
* Pydantic'in veri yapıları aslında sadece senin tanımladığın classlar; Bu yüzden doğrulanmış dataların ile otomatik tamamlama, linting ve mypy'ı kullanarak sorunsuz bir şekilde çalışabilirsin
|
||||||
* **Hızlı**:
|
* **Hızlı**:
|
||||||
* <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">Benchmarklarda</a>, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı.
|
* <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">Benchmarklarda</a>, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı.
|
||||||
* **En kompleks** yapıları bile doğrula:
|
* **En kompleks** yapıları bile doğrula:
|
||||||
* Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula.
|
* Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula.
|
||||||
* Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor
|
* Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor
|
||||||
|
|
@ -206,4 +206,3 @@ Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiy
|
||||||
* **Genişletilebilir**:
|
* **Genişletilebilir**:
|
||||||
* Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor.
|
* Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor.
|
||||||
* 100% test kapsayıcılığı.
|
* 100% test kapsayıcılığı.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ $ pip install uvicorn[standard]
|
||||||
* `main.py` adında bir dosya oluştur :
|
* `main.py` adında bir dosya oluştur :
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -170,7 +170,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
Eğer kodunda `async` / `await` var ise, `async def` kullan:
|
Eğer kodunda `async` / `await` var ise, `async def` kullan:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -193,7 +193,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -272,7 +272,7 @@ Senin için alternatif olarak (<a href="https://github.com/Rebilly/ReDoc" class=
|
||||||
Şimdi Pydantic sayesinde, Python'un standart tiplerini kullanarak bir body tanımlayacağız.
|
Şimdi Pydantic sayesinde, Python'un standart tiplerini kullanarak bir body tanımlayacağız.
|
||||||
|
|
||||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -283,7 +283,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -292,7 +292,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -455,7 +455,6 @@ Pydantic tarafında kullanılan:
|
||||||
Starlette tarafında kullanılan:
|
Starlette tarafında kullanılan:
|
||||||
|
|
||||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Eğer `TestClient` kullanmak istiyorsan gerekli.
|
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Eğer `TestClient` kullanmak istiyorsan gerekli.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - `FileResponse` ya da `StaticFiles` kullanmak istiyorsan gerekli.
|
|
||||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Eğer kendine ait template konfigürasyonu oluşturmak istiyorsan gerekli
|
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Eğer kendine ait template konfigürasyonu oluşturmak istiyorsan gerekli
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Form kullanmak istiyorsan gerekli <abbr title="HTTP bağlantısından gelen stringi Python objesine çevirmek için">("dönüşümü")</abbr>.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Form kullanmak istiyorsan gerekli <abbr title="HTTP bağlantısından gelen stringi Python objesine çevirmek için">("dönüşümü")</abbr>.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` desteği için gerekli.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` desteği için gerekli.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
|
||||||
* Create a file `main.py` with:
|
* Create a file `main.py` with:
|
||||||
|
|
||||||
```Python
|
```Python
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||||
If your code uses `async` / `await`, use `async def`:
|
If your code uses `async` / `await`, use `async def`:
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
```Python hl_lines="9 14"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ async def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||||
Declare the body using standard Python types, thanks to Pydantic.
|
Declare the body using standard Python types, thanks to Pydantic.
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
```Python hl_lines="4 9-12 25-27"
|
||||||
from typing import Optional
|
from typing import Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -275,7 +275,7 @@ app = FastAPI()
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
price: float
|
price: float
|
||||||
is_offer: Optional[bool] = None
|
is_offer: Union[bool, None] = None
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
@ -284,7 +284,7 @@ def read_root():
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
@app.get("/items/{item_id}")
|
||||||
def read_item(item_id: int, q: Optional[str] = None):
|
def read_item(item_id: int, q: Union[str, None] = None):
|
||||||
return {"item_id": item_id, "q": q}
|
return {"item_id": item_id, "q": q}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -447,7 +447,6 @@ Used by Pydantic:
|
||||||
Used by Starlette:
|
Used by Starlette:
|
||||||
|
|
||||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@ theme:
|
||||||
name: material
|
name: material
|
||||||
custom_dir: overrides
|
custom_dir: overrides
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- media: "(prefers-color-scheme: light)"
|
||||||
|
scheme: default
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
icon: material/lightbulb
|
icon: material/lightbulb
|
||||||
name: Switch to light mode
|
name: Switch to light mode
|
||||||
- scheme: slate
|
- media: "(prefers-color-scheme: dark)"
|
||||||
|
scheme: slate
|
||||||
primary: teal
|
primary: teal
|
||||||
accent: amber
|
accent: amber
|
||||||
toggle:
|
toggle:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
要实现它,导入 `JSONResponse`,然后在其中直接返回你的内容,并将 `status_code` 设置为为你要的值。
|
要实现它,导入 `JSONResponse`,然后在其中直接返回你的内容,并将 `status_code` 设置为为你要的值。
|
||||||
|
|
||||||
```Python hl_lines="2 19"
|
```Python hl_lines="4 25"
|
||||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,4 +62,3 @@
|
||||||
但是你仍可以参考 [OpenApI 中的额外响应](additional-responses.md){.internal-link target=_blank} 给响应编写文档。
|
但是你仍可以参考 [OpenApI 中的额外响应](additional-responses.md){.internal-link target=_blank} 给响应编写文档。
|
||||||
|
|
||||||
在后续的章节中你可以了解到如何使用/声明这些自定义的 `Response` 的同时还保留自动化的数据转换和文档等。
|
在后续的章节中你可以了解到如何使用/声明这些自定义的 `Response` 的同时还保留自动化的数据转换和文档等。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋
|
||||||
|
|
||||||
他们主要通过<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>支持我在 **FastAPI** (和其他项目)的工作。
|
他们主要通过<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>支持我在 **FastAPI** (和其他项目)的工作。
|
||||||
|
|
||||||
|
{% if sponsors %}
|
||||||
|
|
||||||
{% if sponsors.gold %}
|
{% if sponsors.gold %}
|
||||||
|
|
||||||
### 金牌赞助商
|
### 金牌赞助商
|
||||||
|
|
@ -141,6 +143,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
### 个人赞助
|
### 个人赞助
|
||||||
|
|
||||||
{% if github_sponsors %}
|
{% if github_sponsors %}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue