10.1. Je eerste endpoint

Voordat de cam iets interessants kan doen, moet de rest van het netwerk hem kunnen bereiken. Het goedkoopste wat bewijst dat de server actief is, is een HTTP-endpoint met één route die wat JSON teruggeeft:

from microdot import Microdot

app = Microdot()

frame_count = 0
trigger_count = 0

@app.get('/status')
async def status(request):
    return {'frames': frame_count, 'triggers': trigger_count}

app.run(host='0.0.0.0', port=80)

Voer het uit in de IDE. Open vanaf een willekeurige andere machine op het LAN http://<cam-ip>/status. De browser toont:

{"frames": 0, "triggers": 0}

De tellers zijn tijdelijke plaatshouders – niets raakt ze nog aan – maar het verzoek heeft het netwerk overgestoken, de cam heeft het gerouteerd, een handler uitgevoerd en JSON teruggestuurd.

10.1.1. Wat elke regel doet

Eén microdot.Microdot instantie per script. De instantie beheert de routeringstabel, de foutafhandelaars en de levenscyclus (start, serveren, stop). Grote applicaties splitsen op in meerdere Python-modules, maar delen nog steeds één app object.

@app.get('/status') is de route-decorator. We gebruiken hier alleen microdot.Microdot.get(); post(), put() en delete() komen op latere pagina’s aan bod wanneer de cam schrijfacties gaat accepteren.

Elke route-handler is een asyncio-coroutine en ontvangt het verzoek als zijn eerste argument. De handler hoeft request niet te gebruiken – deze negeert het – maar de parameter is er altijd, zodat de signatuur consistent blijft.

Een dict teruggeven is de kortste manier om JSON te versturen. Microdot serialiseert de dict automatisch naar JSON en stelt Content-Type: application/json in op de respons. Een string teruggeven verstuurt text/plain. Expliciet een microdot.Response teruggeven is de lange vorm – nodig wanneer de body binair is of wanneer de respons aangepaste headers wil.

app.run(host='0.0.0.0', port=80) start de server. 0.0.0.0 betekent luister op elke interface die de cam heeft – zowel het bekabelde ethernet als de wifi-STA, als beide actief zijn. Poort 80 is de HTTP-standaard, zodat browsers geen poortnummer hoeven in te typen.

10.1.2. Eén verzoek, van begin tot eind

De telefoon opent een TCP-verbinding met de cam, verstuurt een HTTP- verzoek, de cam parseert, routeert, voert de handler uit en schrijft vervolgens een respons terug.

De telefoon opent een TCP-verbinding, schrijft de verzoekregel en headers, en wacht. De cam leest de bytes van de socket, parseert ze tot een microdot.Request object, vergelijkt het pad en de methode met de routeringstabel, awaits de handler-coroutine, serialiseert wat die ook teruggaf, schrijft een statusregel, headers en body terug naar de socket, en sluit dan de verbinding (HTTP/1.0-standaard) of hergebruikt deze (HTTP/1.1 met Connection: keep-alive). De hele uitwisseling duurt ongeveer zo lang als de netwerk-rondreis plus wat de handler ook deed.

10.1.3. Een opmerking over blokkeren

run() is blokkerend – het keert nooit terug totdat de server stopt. Dat is prima voor een server met één doel. Een app die ook frames vastlegt of andere coroutines draait, gebruikt in plaats daarvan start_server() binnen een asyncio.run(), zodat de HTTP-server de loop kan delen met al het andere.

De app beantwoordt één URL.