10.5. 相機的控制 API

擁有者需要能從任何地方設定動作偵測器的靈敏度——在颳風的日子裡,風會更劇烈地搖動樹木。這代表需要一些路由,讓儀表板可以從中讀取目前的設定,並向其張貼變更。

模組上一個小巧的共享狀態 dict 就足以容納這些調節旋鈕。後續的頁面會為它加入更多鍵;目前只有一個:

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

10.5.1. 以 GET 讀取,以 POST 寫入

一對路由——一個 get、一個 post——讓儀表板對 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 會回傳解析為 JSON 的主體,若 Content-Type 不是 application/json 則回傳 Nonepost 處理常式會逐一走過每一種故障模式——缺少鍵、型別錯誤、超出範圍——並以 microdot.abort() 中止,後者會拋出 microdot.HTTPException,以給定的狀態與訊息將處理常式短路。

10.5.2. GET、POST、PUT、DELETE

get()post() 是我們最常用的兩個。put()delete() 則為遵循 REST 慣例的情況而存在——以 PUT /events/42 取代事件 42,以 DELETE /events/42 將其刪除。處理常式在其餘方面則完全相同。

10.5.3. 讀取查詢字串與表單

儀表板張貼的是 JSON,所以 request.json 正是我們要的。相機還可能透過另外兩種方式接收資料:

  • args——查詢字串。?foo=1&bar=2 會變成一個 microdot.MultiDict,你可以用 request.args.get('foo') 讀取它。

  • form——以 application/x-www-form-urlencoded 張貼的 HTML 表單。同樣是 MultiDict 型別。

MultiDict 類似 dict,但允許一個鍵攜帶多個值(?tag=cat&tag=dog 就是兩個 tag 值);完整介面請參閱 microdot.MultiDict

10.5.4. 動態 URL 區段

路由路徑可以宣告具型別的佔位符,microdot 會把它們作為額外引數傳給處理常式:

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

支援的轉換器有 <int:>、用於自訂正規表示式的 <re:>、用於可包含斜線之區段的 <path:>,以及預設(無前綴)的「比對直到下一個斜線為止的任何內容」。<int:event_id> 接受 /events/42 並拒絕 /events/abc——遭拒會變成 404,處理常式不會執行。

10.5.5. 自訂錯誤回應

microdot 預設送出的 404 是純文字的 Not found。儀表板期望每個回應都是 JSON;請覆寫 404 處理常式,讓它同樣回傳 JSON:

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

errorhandler() 接受狀態碼(攔截該狀態的所有錯誤)或例外類別(攔截每一個拋出該例外的處理常式)。(body, status) 元組會將回應短路,而無需建構一個 Response

相機現在會公開其狀態並接受編輯了。