Ga naar hoofdinhoud

Invoer controleren: de inhoud controleren

max_length uit les 3 bewaakt de lengte, en een leeg veld weigert FastAPI al, zoals je in les 4 zag. Maar een naam van drie spaties is niet leeg en niet te lang. Maak een script spaties.py dat zo'n naam stuurt:

import httpx

antwoord = httpx.post("http://127.0.0.1:8000/bericht", data={"naam": " ", "bericht": "hoi"})
print(antwoord.status_code, antwoord.json())

Uitvoer:

200 {'lengte': 3}

Draai lees_database.py uit les 1. Onderaan staat het nieuwe bericht:

[ ] 3 tekens

Tussen de blokhaken staan drie spaties: in je gastenboek staat nu een bericht zonder zichtbare naam. Dat een naam uit meer dan spaties bestaat, controleer je zelf.

strip()​

strip() haalt de spaties aan het begin en het eind van een tekst weg:

print(repr(" ".strip()))
print(repr(" Sara ".strip()))

Uitvoer:

''
'Sara'

repr laat de aanhalingstekens zien, zodat je de spaties ziet. Blijft er na strip() niets over, dan bestond de naam alleen uit spaties.

De controle in het endpoint​

@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(..., max_length=30),
bericht: str = Form(..., max_length=280),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}
  1. Regel 6:

    Een lege tekst telt in een if als niet waar, dus not naam.strip() is waar als er niets overblijft.

  2. Regel 7:

    raise HTTPException stopt de functie en stuurt een foutmelding, zoals de 404 in Een 404 sturen: als het item niet bestaat.

Vervang bericht_plaatsen in je main.py door deze. HTTPException komt uit fastapi, net als Form. Zet hem daarom bij de import bovenaan:

from fastapi import FastAPI, Form, HTTPException

Draai spaties.py opnieuw.

Het is een 400 en geen 422. Een 422 komt van FastAPI zelf, als een veld niet past bij wat er in Form staat. Een 400 stuur meestal jij, voor een regel die je zelf bedacht. De uitzondering zag je in les 2: bij een veld boven een megabyte stuurt Starlette zelf een 400.

Controlevraag
Een naam van drie spaties kwam langs max_length en Form(...). Waarom?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Er gaat iets mis​

JSONDecodeError in spaties.py​

spaties.py stopt met:

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

In de terminal van je server staat:

NameError: name 'HTTPException' is not defined

Oorzaak: HTTPException staat niet bij de import. Je server loopt vast op de regel met raise, en stuurt een 500 met de tekst Internal Server Error. Dat is geen JSON, dus antwoord.json() in je script kan er niets mee.

Oplossing: zet HTTPException bij de import uit fastapi, zoals hierboven. Bij een 500 staat de echte fout altijd in de terminal van je server.

400, maar het bericht staat er toch in​

De server geeft 400, maar lees_database.py laat toch een nieuwe regel met [ ] zien.

Oorzaak: de controle staat ná het opslaan:

# FOUT
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")

# GOED
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()

Oplossing: controleer eerst, en sla pas op als alles klopt.

Opdrachten​

Opdracht 1: Predict - Spaties eromheen​

Je stuurt de naam " Sara ", met een spatie ervoor en erachter.

Vraag: geeft de server 200 of 400? En wat komt er in de database?

Antwoord

200: na strip() blijft Sara over, dus de controle laat hem door. Maar lees_database.py laat [ Sara ] 3 tekens zien, met de spaties, want de controle verandert naam niet. Wil je ze kwijt, zet dan naam = naam.strip() bovenaan de functie.

Opdracht 2: Modify - Ook het bericht​

Zorg dat een bericht van alleen spaties ook een 400 geeft, met de melding Schrijf een bericht.

Tip

Dezelfde twee regels als voor de naam, met bericht in plaats van naam.

Antwoord
@app.post("/bericht")
async def bericht_plaatsen(
naam: str = Form(..., max_length=30),
bericht: str = Form(..., max_length=280),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
if not bericht.strip():
raise HTTPException(status_code=400, detail="Schrijf een bericht")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}

Een bericht van drie spaties geeft nu 400 {'detail': 'Schrijf een bericht'}.

Zo ziet je main.py er nu uit
import time

from fastapi import FastAPI, Form, HTTPException
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),
):
if not naam.strip():
raise HTTPException(status_code=400, detail="Vul een naam in")
with SqliteDict("gastenboek.db") as db:
db[f"bericht_{time.time_ns()}"] = {"naam": naam, "bericht": bericht}
db.commit()
return {"lengte": len(bericht)}

De lengte bewaakt FastAPI, de inhoud jij.

Door naar les 6: getallen met een grens.