10.5. Ett styr-API för kameran

Ägaren behöver kunna ställa in rörelsedetektorns känslighet varifrån som helst – vinden rör träden mer en blåsig dag. Det innebär rutter som instrumentpanelen kan läsa de aktuella inställningarna från och posta ändringar till.

En liten delad tillstånds-dict på modulen räcker för att hålla rattarna. Senare sidor lägger till fler nycklar i den; för tillfället finns det en:

state = {
    'threshold': 12,
    'frame_count': 0,
    'trigger_count': 0,
}

10.5.1. GET för att läsa, POST för att skriva

Ett par rutter – en get, en post – ger instrumentpanelen läs-/skrivåtkomst till 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 returnerar kroppen tolkad som JSON, eller None om Content-Type inte var application/json. post-hanteraren går igenom varje felscenario – saknad nyckel, fel typ, utanför intervallet – och avbryter med microdot.abort(), som genererar microdot.HTTPException för att kortsluta hanteraren med den givna statusen och meddelandet.

10.5.2. GET, POST, PUT, DELETE

get() och post() är de två vi använder mest. put() och delete() finns för fall som följer REST-konventioner – ett PUT /events/42 för att ersätta händelse 42, ett DELETE /events/42 för att ta bort den. Hanteraren är i övrigt identisk.

10.5.3. Läsa frågesträngar och formulär

Instrumentpanelen postar JSON, så request.json är det vi vill ha. Två andra sätt som kameran kan ta emot data på:

  • args – frågesträngen. ?foo=1&bar=2 blir en microdot.MultiDict som du kan läsa med request.args.get('foo').

  • form – ett HTML-formulär postat som application/x-www-form-urlencoded. Samma MultiDict-typ.

MultiDict är dict-liknande men låter en nyckel bära flera värden (?tag=cat&tag=dog är två tag-värden); se microdot.MultiDict för det fullständiga gränssnittet.

10.5.4. Dynamiska URL-segment

En ruttsökväg kan deklarera typade platshållare som microdot skickar till hanteraren som extra argument:

@app.get('/events/<int:event_id>')
async def get_event(request, event_id):
    return {'id': event_id, 'msg': 'placeholder'}

De konverterare som stöds är <int:>, <re:> för ett anpassat reguljärt uttryck, <path:> för ett segment som kan innehålla snedstreck, och standardvärdet (inget prefix) för ”matcha vad som helst fram till nästa snedstreck.” <int:event_id> accepterar /events/42 och avvisar /events/abc – avvisningen blir en 404 utan att hanteraren körs.

10.5.5. Anpassade felsvar

Standard-404:an som microdot skickar är vanlig Not found. Instrumentpanelen förväntar sig JSON för varje svar; åsidosätt 404-hanteraren så att den också returnerar JSON:

@app.errorhandler(404)
async def not_found(request):
    return {'error': 'not found', 'path': request.path}, 404

errorhandler() tar antingen en statuskod (fångar varje fel med den statusen) eller en undantagsklass (fångar varje hanterare som genererade det undantaget). Tupeln (body, status) kortsluter svaret utan att konstruera ett Response.

Kameran exponerar nu sitt tillstånd och accepterar ändringar.