Invoer controleren: grenzen in Form
De grens hoort op de server, waar de bezoeker er niet bij kan. In
Server of browser? schreef je daarvoor zelf
een if met len. FastAPI kan het ook voor je doen: je zet de grens in Form,
en een verzoek dat eroverheen gaat, komt niet eens in je functie.
max_length in Form
@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(..., max_length=30),
bericht: str = Form(..., max_length=280),
):
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}
- Regel 2-5:
De parameters staan nu onder elkaar, want ze zijn te lang voor één regel.
- Regel 3-4:
max_lengthzet de grens: hoogstens 30 tekens voor de naam, 280 voor het bericht. Dezelfde getallen als demaxlengthin de HTML, maar nu telt hij.
Vervang bericht_plaatsen in je main.py door deze. De rest blijft gelijk.
Doe de test opnieuw
Het antwoord op een te lang bericht bevat de hele invoer nog een keer, dus ook
de miljoen letters a. Laat groot.py daarom alleen de statuscode en de
melding printen:
import httpx
adres = "http://127.0.0.1:8000/bericht"
bericht = "a" * 1_000_000
antwoord = httpx.post(adres, data={"naam": "Sara", "bericht": bericht})
print(antwoord.status_code)
print(antwoord.json()["detail"][0]["msg"])
- Regel 8:
Het antwoord heeft een lijst
detailmet een foutmelding per veld. Wat daar precies in staat, zie je in les 3.
Uitvoer:
422
String should have at most 280 characters
Een 422 betekent: het verzoek klopt niet met wat het endpoint verwacht. Het
bericht komt niet in de database, en je eigen code draait niet eens. De
maxlength in de HTML laat je staan: die helpt nog steeds wie zich in de
browser vergist.
Er gaat iets mis
Je draait het oude groot.py, met print(antwoord.json()), en je terminal
loopt vol met letters a.
Oorzaak: bij een 422 stuurt FastAPI in input terug wat er binnenkwam.
Bij een miljoen tekens zijn dat een miljoen letters a.
Oplossing: print alleen wat je nodig hebt, zoals de statuscode en
antwoord.json()["detail"][0]["msg"]. Stop een script dat blijft printen
met Ctrl+C.
Opdrachten
Opdracht 1: Run - Precies op de grens
Stuur een bericht van 280 tekens en een van 281. Welke statuscodes krijg je?
Tip
"a" * 280 maakt 280 letters.
Antwoord
import httpx
adres = "http://127.0.0.1:8000/bericht"
for lengte in [280, 281]:
antwoord = httpx.post(adres, data={"naam": "Sara", "bericht": "a" * lengte})
print(lengte, antwoord.status_code)
Uitvoer:
280 200
281 422
max_length=280 betekent: 280 mag nog, 281 niet.
Opdracht 2: Predict - Een lange naam
Je stuurt een naam van 31 tekens en het bericht hoi.
Vraag: welke statuscode en welke melding krijg je?
Antwoord
422, met de melding String should have at most 30 characters. De grens op
de naam werkt net zo als die op het bericht.
Zo ziet je main.py er nu uit
import time
from fastapi import FastAPI, Form
from fastapi.staticfiles import StaticFiles
from sqlitedict import SqliteDict
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(..., max_length=30),
bericht: str = Form(..., max_length=280),
):
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}
Beide velden hebben nu een grens op de server.
Door naar les 3: een 422 lezen.