10.5. Uma API de controle para a câmera¶
O proprietário precisa ajustar a sensibilidade do detector de movimento de qualquer lugar – o vento move as árvores mais em um dia ventoso. Isso significa rotas das quais o painel possa ler as configurações atuais e às quais possa enviar mudanças.
Um pequeno dict de estado compartilhado no módulo é suficiente para guardar os controles. Páginas posteriores adicionam mais chaves a ele; por enquanto há uma:
state = {
'threshold': 12,
'frame_count': 0,
'trigger_count': 0,
}
10.5.1. GET para ler, POST para escrever¶
Um par de rotas – uma get, uma post – dá ao painel acesso de leitura/escrita ao 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 retorna o corpo analisado como JSON, ou None se o Content-Type não era application/json. O handler post percorre cada modo de falha – chave ausente, tipo errado, fora do intervalo – e desiste com microdot.abort(), que lança microdot.HTTPException para interromper o handler com o status e a mensagem fornecidos.
10.5.2. GET, POST, PUT, DELETE¶
get() e post() são os dois que mais usaremos. put() e delete() existem para casos que seguem as convenções REST – um PUT /events/42 para substituir o evento 42, um DELETE /events/42 para removê-lo. O handler é idêntico no restante.
10.5.3. Lendo query strings e formulários¶
O painel envia JSON, então request.json é o que queremos. Duas outras formas pelas quais a câmera pode receber dados:
args– a query string.?foo=1&bar=2torna-se ummicrodot.MultiDictque você pode ler comrequest.args.get('foo').form– um formulário HTML enviado comoapplication/x-www-form-urlencoded. Mesmo tipoMultiDict.
O MultiDict é semelhante a um dict, mas permite que uma chave carregue múltiplos valores (?tag=cat&tag=dog são dois valores de tag); veja microdot.MultiDict para a interface completa.
10.5.4. Segmentos dinâmicos de URL¶
Um caminho de rota pode declarar marcadores de posição tipados que o microdot passa ao handler como argumentos extras:
@app.get('/events/<int:event_id>')
async def get_event(request, event_id):
return {'id': event_id, 'msg': 'placeholder'}
Os conversores suportados são <int:>, <re:> para um regex personalizado, <path:> para um segmento que pode conter barras, e o padrão (sem prefixo) para “corresponder a qualquer coisa até a próxima barra”. <int:event_id> aceita /events/42 e rejeita /events/abc – a rejeição vira um 404 sem que o handler seja executado.
10.5.5. Respostas de erro personalizadas¶
O 404 padrão que o microdot envia é um simples Not found. O painel espera JSON em toda resposta; sobrescreva o handler de 404 para que ele também retorne JSON:
@app.errorhandler(404)
async def not_found(request):
return {'error': 'not found', 'path': request.path}, 404
errorhandler() recebe ou um código de status (captura todo erro daquele status) ou uma classe de exceção (captura todo handler que lançou aquela exceção). A tupla (body, status) interrompe a resposta sem construir um Response.
A câmera agora expõe seu estado e aceita edições.