Wat je server laat zien: de handleiding uitzetten
In les 2 gaf je server elk sessie-id weg, via een endpoint dat op de handleiding stond. Er zijn twee dingen te doen: de handleiding uit, en het endpoint weg. Je begint met het eerste, en ziet dan waarom het tweede nodig is.
Drie adressen uit
De handleiding staat op drie adressen. /docs ken je uit les 1.
/redoc is dezelfde lijst in een andere opmaak, en /openapi.json is de lijst
zelf. Alle drie zet je uit in de regel waar je app begint:
app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
- Regel 1:
docs_urlis het adres van/docs,redoc_urldat van/redoc, enopenapi_urldat van de lijst. MetNonemaakt FastAPI dat adres niet aan.
Vervang je regel app = FastAPI() door deze. De rest van main.py blijft.
Doe de test
Maak een script dicht.py dat de vier adressen afloopt:
import httpx
for pad in ["/docs", "/redoc", "/openapi.json", "/sessies"]:
antwoord = httpx.get("http://127.0.0.1:8000" + pad)
print(pad, antwoord.status_code)
Uitvoer:
/docs 404
/redoc 404
/openapi.json 404
/sessies 200
De handleiding is weg: een 404, alsof het adres nooit bestond. Maar
/sessies antwoordt nog. Draai sessies.py uit les 2, en je krijgt dezelfde
sessie-id's als eerst.
Verstoppen is geen slot
Wie het pad /sessies kent, heeft de handleiding niet nodig. Hij heeft het
bijvoorbeeld eerder gezien, voordat je de handleiding uitzette, of hij probeert
een paar voor de hand liggende namen. De lijst uitzetten maakt een gat moeilijker
te vinden, maar het gat blijft. Iets beveiligen door het te verstoppen heet
security through obscurity, en het houdt niemand tegen die het toch vindt.
Haal daarom het endpoint zelf weg. Verwijder alle_sessies met zijn
@app.get("/sessies") uit main.py, en draai dicht.py opnieuw:
/docs 404
/redoc 404
/openapi.json 404
/sessies 404
Nu valt er niets te vinden en niets te gebruiken. Draai je sessies.py nog
een keer, dan print het één vreemde regel:
detail {'naam': 'onbekend'}
Het script leest de 404-melding {"detail": "Not Found"} alsof het een lijst
met sessies is, en probeert detail als sessie-id. Je server kent dat niet.
Waar de controle zit
Wat je server laat zien, bepaal je in main.py: met de drie instellingen, en
met welke endpoints er staan. De bezoeker kan alleen gebruiken wat er is.
Browser: Een bezoeker opent /docs. Of /openapi.json: daar stond de lijst met al je endpoints. · De handleiding op /docs
Hier zit de controleServer: FastAPI zoekt het pad. Met docs_url, redoc_url en openapi_url op None bestaat de handleiding niet: 404. · De handleiding uitzetten
Browser: Hij probeert een pad dat hij kent. Bijvoorbeeld GET /sessies, van een lijst die hij eerder zag. · Een vergeten endpoint
Hier zit de controleServer: Staat het endpoint in main.py?. Alleen wat er staat, antwoordt. Een weggehaald endpoint geeft een 404. · De handleiding uitzetten
Browser: Hij krijgt twee keer een 404. Er valt niets te vinden en niets te gebruiken.
Er gaat iets mis
Je hebt de handleiding uitgezet, maar in de terminal van fastapi dev staat nog
steeds:
Documentation at http://127.0.0.1:8000/docs
Oorzaak: fastapi dev print die regel altijd bij het starten, ook als je
app geen /docs heeft. Hij kijkt niet in je instellingen.
Oplossing: niets, je server doet het goed. Kijk met dicht.py of in de
browser wat er echt op /docs staat: een 404 met
{"detail":"Not Found"}.
Opdrachten
Opdracht 1: Predict - Alleen docs_url
Je zet alleen app = FastAPI(docs_url=None) en draait dicht.py, met
/sessies nog in je main.py.
Vraag: welke vier statuscodes print het script?
Tip
Elke instelling zet één adres uit.
Antwoord
/docs 404
/redoc 200
/openapi.json 200
/sessies 200
Alleen /docs is weg. Op /redoc staat dezelfde lijst in een andere opmaak, en
/openapi.json is de lijst zelf. Daarom zet je ze alle drie op None.
Opdracht 2: Investigate - Alleen openapi_url
Probeer nu app = FastAPI(openapi_url=None), zonder de andere twee. Wat geeft
dicht.py voor /docs en /redoc, en waarom?
Antwoord
Allebei 404. De pagina's op /docs en /redoc lezen hun lijst uit
/openapi.json, zoals je in les 1 zag. Zonder die lijst maakt FastAPI ze niet
aan. Zet de andere twee er toch bij: dan ziet wie je main.py leest, dat de
handleiding bewust uit staat.
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(docs_url=None, redoc_url=None, openapi_url=None)
@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")}
De handleiding staat uit, en GET /sessies is weg. In de volgende lessen
verandert main.py niet meer: die gaan over de bestanden naast je code.
Door naar les 4: wat er in je map staat.