10.5. Een besturings-API voor de cam#
De eigenaar moet de gevoeligheid van de bewegingsdetector overal vandaan kunnen instellen – de wind beweegt bomen meer op een winderige dag. Dat betekent routes waaruit het dashboard de huidige instellingen kan lezen en waaraan het wijzigingen kan posten.
Een kleine gedeelde state-dict op de module is genoeg om de knoppen te bevatten. Latere pagina’s voegen er meer sleutels aan toe; voorlopig is er één:
state = {
'threshold': 12,
'frame_count': 0,
'trigger_count': 0,
}
10.5.1. GET om te lezen, POST om te schrijven#
Een paar routes – één get en één post – geeft het dashboard lees- en schrijftoegang tot state:
from microdot import abort
@app.get('/config')
async def get_config(request):
return state
@app.post('/config')
async def set_config(request):
body = request.json
if not body or 'threshold' not in body:
abort(400, 'missing threshold')
try:
threshold = int(body['threshold'])
except (TypeError, ValueError):
abort(400, 'threshold must be an integer')
if not 0 <= threshold <= 100:
abort(400, 'threshold out of range')
state['threshold'] = threshold
return {'ok': True, 'threshold': threshold}
microdot.Request.json geeft de body terug, geparseerd als JSON, of None als Content-Type niet application/json was. De post-handler loopt elke faalmodus af – ontbrekende sleutel, verkeerd type, buiten bereik – en breekt af met microdot.abort(), die een microdot.HTTPException opwerpt om de handler kort te sluiten met de opgegeven status en melding.
10.5.2. GET, POST, PUT, DELETE#
get() en post() zijn de twee die we het meest zullen gebruiken. put() en delete() bestaan voor gevallen die de REST-conventies volgen – een PUT /events/42 om event 42 te vervangen, een DELETE /events/42 om het te verwijderen. De handler is verder identiek.
10.5.3. Query strings en formulieren lezen#
Het dashboard post JSON, dus request.json is wat we willen. Twee andere manieren waarop de cam gegevens kan ontvangen:
args– de query string.?foo=1&bar=2wordt eenmicrodot.MultiDictdie je kunt lezen metrequest.args.get('foo').form– een HTML-formulier dat alsapplication/x-www-form-urlencodedis gepost. HetzelfdeMultiDict-type.
De MultiDict is dict-achtig, maar laat één sleutel meerdere waarden dragen (?tag=cat&tag=dog zijn twee tag-waarden); zie microdot.MultiDict voor het volledige oppervlak.
10.5.4. Dynamische URL-segmenten#
Een routepad kan getypeerde plaatshouders declareren die microdot als extra argumenten aan de handler doorgeeft:
@app.get('/events/<int:event_id>')
async def get_event(request, event_id):
return {'id': event_id, 'msg': 'placeholder'}
De ondersteunde converters zijn <int:>, <re:> voor een aangepaste regex, <path:> voor een segment dat schuine strepen kan bevatten, en de standaard (geen prefix) voor “match alles tot de volgende schuine streep.” <int:event_id> accepteert /events/42 en weigert /events/abc – de weigering wordt een 404 zonder dat de handler draait.
10.5.5. Aangepaste foutresponses#
De standaard 404 die microdot stuurt is gewoon Not found. Het dashboard verwacht JSON voor elke response; overschrijf de 404-handler zodat hij ook JSON teruggeeft:
@app.errorhandler(404)
async def not_found(request):
return {'error': 'not found', 'path': request.path}, 404
errorhandler() neemt ofwel een statuscode (vangt elke fout van die status) ofwel een uitzonderingsklasse (vangt elke handler die die uitzondering opwierp). De (body, status)-tuple sluit de response kort zonder een Response te construeren.
De cam stelt nu zijn state beschikbaar en accepteert wijzigingen.