Lekce 3 - Path a query parametry ve FastAPI
V minulé lekci, Seznámení s FastAPI frameworkem pro Python, jsme si vytvořili svou první webovou aplikaci ve frameworku FastAPI pro Python. Založili jsme projekt a vypsali hlášku "Hello World".
V dnešním tutoriálu webových aplikací s frameworkem FastAPI se podíváme na rozdíl mezi path a query parametry. Vysvětlíme si význam a výhody typových anotací a zaměříme se také na nepovinné parametry funkcí.
V průběhu kurzu postupně vytvoříme filmovou databázi. Příklady (proměnné, názvy tříd, parametry a podobně) tedy budeme pojmenovávat v tomto duchu už teď, i když samotný projekt začneme tvořit až v pozdějších lekcích.
Parametry path vs. query
Parametr path ("parametr cesty") je parametr požadavku vložený do URL
adresy, který ukazuje na specifickou lokalitu zdroje. V URL je oddělen
lomítkem od domény, například v URL
https://example.com/movies/1/
je číslovka jedna path parametrem
(konkrétně se jedná o id
filmu, jak uvidíme později). Tento
parametr je povinnou součástí požadavku na server a musí tedy vždy nést
nějakou hodnotu, kterou je možné změnit, protože je dynamická. Oproti tomu
je část /movies/
v URL výše považována za součást cesty,
která je pevně daná, neměnná.
Zatímco path identifikuje lokalitu zdroje a říká tak naší aplikaci,
KAM se má podívat, query parametr ("dotazovací parametr") se
používá k posílání a filtrování dat uvnitř požadavku. Říká
aplikaci, JAK se podívat do určitého zdroje. Uživatelský
vstup (query) je poslán jako proměnná do query parametru, který je od URL
oddělený otazníkem. Query parametry lze také řetězit. Oddělují se od
sebe pomocí znaku apersand (&
). Například v URL
https://example.com/movies/?id=1&movie_name=Star%20Wars
posíláme dotazy na id
, které se má rovnat 1
, a
movie_name
, které se má rovnat Star Wars
. Query
parametry nejsou povinnou součástí požadavku na server, pomáhají však
získat podrobnější či přesnější data.
Kombinace znaků %20
v URL značí mezeru.
Ukažme si, jak se oba typy parametrů definují v aplikacích vytvořených pomocí FastAPI.
Path parametry
Začneme tím, že si parametr path vyzkoušíme na naší aplikaci Hello World. Aplikaci si otevřeme v IDE. V terminálu ji pak spustíme:
Spuštění aplikace:
uvicorn main:app --reload
Od minule přibyla v příkazu pro spuštění serveru část
--reload
. Díky ní server sleduje změny v kódu uvedeného
zdroje, a pokud nějaké zaznamená, automaticky obnoví stránku, což se při
vývoji skvěle hodí.
Aplikace se spustí na localhostu (http://127.0.0.1:8000/). Otevřeme si ji v prohlížeči.
V IDE otevřeme její soubor main.py
a pod funkci
index()
přidáme jednu novou. Funkce se bude jmenovat
read_movie()
. Jako argument přijme path parametr
movie_id
a vrátí nám film s odpovídajícím
id
:
@app.get("/movies/{movie_id}") async def read_movie(movie_id): return {"movie_id": movie_id}
Syntaxe připomíná formátovaný řetězec. Hodnota path parametru
movie_id
(v dekorátoru funkce je uvedená ve složených
závorkách) je dynamická a bude poslána do funkce jako argument
movie_id
v závislosti na požadavku uživatele.
Adresu localhostu doplníme o /movies/1
tak, aby vypadala takto:
http://127.0.0.1:8000/movies/1
. Potvrdíme stiskem Enter
a vypíše se nám:
Pokud budeme měnit poslední číslici v URL, bude se odpovídajícím
způsobem měnit i id
zobrazené na stránce.
Typové anotace a jejich přednosti
FastAPI umí přijímat i typové anotace. Nejsou povinné, ale jedná se o
dobrou praxi, kterou budeme dodržovat. Má to jen výhody. Definici funkce
read_movie()
upravíme takto:
@app.get("/movies/{movie_id}") async def read_movie(movie_id: int): return {"movie_id": movie_id}
Definovali jsme, že funkce read_movie()
přijme jako parametr
movie_id
pouze typ int
. Tento
nepatrný přípisek má velké důsledky. Díky němu nám naše IDE nabídnou
nejrůznější podporu uvnitř takové funkce, například zkontrolují
chyby, nabídnou automatické dokončení apod. Pokud
navíc nyní navštívíme http://127.0.0.1:8000/movies/1
,
všimneme si, že se nám tentokrát vypsalo:
Ano, id
filmu se pošle a vrátí jako int
, nikoliv
jako str
v předchozí variantě. Takže tím, že deklarujeme typ
parametru, nám FastAPI ke všem dříve jmenovaným výhodám přidá ještě
automatické parsování a také validaci dat.
Kdybychom totiž zkusili navštívit například http://127.0.0.1:8000/movies/jedna,
vrátí se nám docela podrobná chybová hláška upozorňující na nemožnost
zpracovat str
namísto int
, který daná funkce
vyžaduje:
Query parametry
Odeslání požadavku na konkrétní data máme vyřešené a přejdeme tedy
k filtrování dat. Nejdříve si vytvoříme malou improvizovanou databázi,
ať máme v čem hledat. Jako databáze nám poslouží slovník obsahující
několik dalších slovníků s údaji o filmech a jejich režisérech. Pro
jednoduchost stále pracujeme v main.py
:
movie_db = { 1: {"movie_name": "Star Wars", "director": "George Lucas"}, 2: {"movie_name": "Frozen", "director": "Adam Green"}, 3: {"movie_name": "Shrek", "director": "Vicky Jenson"}, }
Naše funkce pro vyhledávání filmů podle parametrů se bude jmenovat
find_movie
. Dekorátor a hlavička funkce budou podobné těm
předchozím, ale tělo se bude lišit. Vytvoříme tedy ještě jednu novou
funkci:
@app.get("/movies/") async def find_movie(movie_name: str): result = {"message": "Movie not found"} for movie_id, movie in movie_db.items(): if movie["movie_name"].lower() == movie_name.lower(): result = {"movie_id": movie_id, "movie_details": movie} break return result
Všimněme si, že v dekorátoru tentokrát chybí dynamický path parametr
movie_id
a URL končí pevným parametrem /movies/
.
Naše funkce přijímá parametr movie_name
ve formátu
str
. Do proměnné result
jsme si uložili chybovou
hlášku pro případ, že se vyhledávání nezdaří. Poté projdeme pomocí
for
cyklu naši improvizovanou databázi a pokud v ní požadované
jméno filmu převedené na malé znaky nenajdeme, vrátíme uživateli
připravenou chybovou zprávu. Pokud uspějeme, vrátíme upravenou zprávu
obsahující id filmu a jeho detaily v podobě názvu a režiséra a ukončíme
cyklus, protože je zbytečné pokračovat v hledání.
Pokud si nyní otevřeme
http://localhost:8000/movies/?movie_name=Frozen
, dostaneme
zpět:
Různé prohlížeče si výstup formátují po svém. Takto v řádku jej zobrazí Opera a Chrome, no a Edge si jej rozloží na sedm řádků. Na to je třeba myslet a výstup do prohlížeče případně naformátovat nuceně pomocí JavaScriptu nebo HTML šablony. Obojí si ukážeme dále v kurzu.
Volitelné parametry a výchozí hodnoty
Ve vyhledávání se rozhodně nemusíme omezovat na jeden parametr.
Nestačí ale pouze připsat další parametr do funkce, musíme z nich také
udělat nepovinné parametry. Toho docílíme tím, že u nich
umožníme zadat hodnotu None
a definujeme jí výchozí
hodnotu. Přidejme si vyhledávání podle režiséra:
@app.get("/movies/") async def find_movie(movie_name: str | None = None, director: str | None = None): result = {"message": "Movie not found"} if movie_name is None and director is None: return result for movie_id, movie in movie_db.items(): if (movie_name is None or movie["movie_name"].lower() == movie_name.lower()) and \ (director is None or movie["director"].lower() == director.lower()): result = {"movie_id": movie_id, "movie_details": movie} break return result
Znak "|" na české klávesnici napíšeme pomocí AltGr + W.
Parametry naší funkce jsou nyní movie_name
a
director
– oboje typu str
nebo
None
. V případě, že uživatelský požadavek nebude
movie_name
a/nebo director
obsahovat (tedy parametry
budou mít hodnotu None
), použije funkce jejich výchozí hodnotu,
což je v obou případech None
(proto je zápis
None = None
, pokud není zadaná hodnota, použitý jako výchozí
None
).
Tělo funkce jsme také upravili, aby stačilo v databázi najít jen jeden
ze záznamů a vrátil se správný výsledek. Pokud budou oba parametry
None
(tedy při pokusu o navštívení
http://localhost:8000/movies/
), hledání v databázi ani
neproběhne a vrátí se hned zpráva o nenalezení filmu.
Pokud nyní navštívíme
http://localhost:8000/movies/?movie_name=Shrek
nebo
http://localhost:8000/movies/?director=Vicky%20Jenson
, uvidíme v
obou případech shodně:
Zdrojový kód je opět přiložený v archivu na konci lekce.
V následujícím kvízu, Kvíz - Základy FastAPI, parametry path a query, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkamiStaženo 104x (915 B)