Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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:

Použití parametru path:
http://127.0.0­.1:8000/movies/1

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:

FastAPI reaguje na typovou anotaci:
http://127.0.0­.1:8000/movies/1

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:

Chyba při nedodržení typu:
http://127.0.0­.1:8000/movies/jed­na

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:

Filtrování pomocí query:
http://127.0.0­.1:8000/movies/?mo­vie_name=Frozen

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ě:

Filtrování pomocí query:
http://localhos­t:8000/movies/?di­rector=Vicky%20Jen­son

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ínkami

Staženo 53x (915 B)

 

Předchozí článek
Seznámení s FastAPI frameworkem pro Python
Všechny články v sekci
FastAPI - Tvorba webů v Pythonu
Přeskočit článek
(nedoporučujeme)
Kvíz - Základy FastAPI, parametry path a query
Článek pro vás napsal Tomáš Severa
Avatar
Uživatelské hodnocení:
3 hlasů
Aktivity