Wat je server laat zien: de handleiding op /docs
Hier bouw je op verder: Door een dictionary lopen
Weet je dit niet meer zeker? Lees het terug voordat je verdergaat.
- Python Door een dictionary lopen
In de terminal van je server staat sinds les 1
een tweede adres, met /docs erachter. Je kijkt wat daar staat, en voor wie.
Open /docs
Open http://127.0.0.1:8000/docs in je browser. Je ziet een pagina die je nooit
hebt gemaakt, met een regel per endpoint:
POST /bericht Bericht Plaatsen
GET /berichten Berichten
GET /ik Wie Ben Ik
GET /sessies Alle Sessies
FastAPI maakt die pagina zelf, uit je main.py: elk pad, elke methode, en de
naam van je functie met hoofdletters. Klap je een regel open, dan zie je ook
welke velden en cookies het endpoint verwacht. Met de knop Try it out kun je
het endpoint vanaf die pagina gebruiken, zonder formulier.
Voor jou als bouwer is dat handig. Maar de pagina staat er voor iedereen die je server kan bereiken, en niet alleen voor jou.
Dezelfde lijst als JSON
De pagina op /docs leest zijn lijst uit een ander adres: /openapi.json. Daar
staat dezelfde beschrijving als JSON, in een vaste vorm die OpenAPI heet. Een
script kan hem dus ook lezen. Maak naast main.py een bestand
handleiding.py:
import httpx
antwoord = httpx.get("http://127.0.0.1:8000/openapi.json")
for pad, methoden in antwoord.json()["paths"].items():
for methode in methoden:
print(methode.upper(), pad)
- Regel 4:
Onder
pathsstaat een dictionary met elk pad als sleutel..items()geeft het pad en wat erbij hoort. - Regel 5-6:
Bij elk pad staan de methoden, zoals
getofpost.upper()maakt er hoofdletters van.
Draai het in een tweede terminal, zoals in Een script als bezoeker.
Wie er nog meer bij kan
Zolang je server op 127.0.0.1 draait, kan alleen jij bij /docs. Zet je hem
open zoals in Laat het aan anderen zien, met
--host 0.0.0.0, dan kan iedereen op het netwerk het netwerkadres van je
computer typen met :8000/docs erachter. Je klasgenoot ziet dan dezelfde lijst
als jij, met het endpoint dat je vergeten bent weg te halen. Wat dat kost, zie
je in les 3.
Er gaat iets mis
/docs blijft wit
/docs blijft een witte pagina, terwijl /openapi.json wel een lange tekst
toont.
Oorzaak: de pagina op /docs haalt zijn opmaak en zijn script van internet,
van cdn.jsdelivr.net. Blokkeert het netwerk dat, of heb je geen internet, dan
blijft de pagina leeg. Je server doet niets fout.
Oplossing: gebruik /openapi.json of het script handleiding.py. Daarin
staat dezelfde lijst, en die komt van je eigen server.
Opdrachten
Opdracht 1: Predict - Een endpoint erbij
Je zet dit endpoint onderaan main.py, en draait handleiding.py opnieuw:
@app.get("/tijd")
async def tijd():
return {"tijd": time.time()}
Vraag: wat print het script nu?
Tip
FastAPI maakt de lijst uit wat er op dat moment in main.py staat.
Antwoord
POST /bericht
GET /berichten
GET /ik
GET /sessies
GET /tijd
Het nieuwe endpoint staat er meteen bij. Je hoeft niets bij te houden: wat in
main.py staat, staat ook in de handleiding. Haal /tijd daarna weer weg.
Opdracht 2: Run - Een bericht via /docs
Open /docs, klap POST /bericht open en klik op Try it out. Laat het vak
sessie_id leeg, en vul bij naam en bericht iets in; in die vakken staat al
het woord string, dat vervang je. Klik op Execute. Open daarna
/berichten. Staat je bericht erbij?
Antwoord
Ja. Onder Execute zie je het antwoord, met opgeslagen en de sleutel, en op
/berichten staat je bericht in de lijst. De pagina op /docs stuurt hetzelfde
verzoek als een formulier of een script. Wie de pagina kan openen, kan elk
endpoint dus ook gebruiken, zonder je HTML te zien.
Zo ziet je main.py er nu uit
import secrets
import time
from fastapi import Cookie, FastAPI, Form
from fastapi.responses import JSONResponse
from sqlitedict import SqliteDict
app = FastAPI()
@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(...),
bericht: str = Form(...),
sessie_id: str = Cookie(default=""),
):
if not sessie_id:
sessie_id = secrets.token_hex(16)
sleutel = f"bericht_{time.time_ns()}"
with SqliteDict("gastenboek.db") as db:
db[sleutel] = {"naam": naam, "bericht": bericht}
db.commit()
with SqliteDict("sessies.db") as sessies:
mijn = sessies.get(sessie_id, {"naam": naam, "berichten": []})
mijn["naam"] = naam
mijn["berichten"].append(sleutel)
sessies[sessie_id] = mijn
sessies.commit()
antwoord = JSONResponse({"opgeslagen": sleutel})
antwoord.set_cookie(key="sessie_id", value=sessie_id, httponly=True, samesite="lax")
return antwoord
@app.get("/berichten")
async def berichten():
with SqliteDict("gastenboek.db") as db:
return list(db.values())
@app.get("/ik")
async def wie_ben_ik(sessie_id: str = Cookie(default="")):
with SqliteDict("sessies.db") as sessies:
mijn = sessies.get(sessie_id, {})
return {"naam": mijn.get("naam", "onbekend")}
@app.get("/sessies")
async def alle_sessies():
with SqliteDict("sessies.db") as sessies:
return dict(sessies)
Dit is nog steeds de beginstand uit les 1. In les 4 verandert de regel met
app = FastAPI(), en gaat GET /sessies eruit.
Door naar les 3: een vergeten endpoint.