10.5. Control API สำหรับกล้อง

เจ้าของต้องการตั้งค่าความไวของระบบตรวจจับการเคลื่อนไหวจากทุกที่ — วันที่ลมแรง ต้นไม้เคลื่อนไหวมากขึ้น ซึ่งหมายความว่าต้องมี route ที่แดชบอร์ดสามารถอ่านค่าการตั้งค่าปัจจุบันและส่งการเปลี่ยนแปลงได้

dict สถานะขนาดเล็กที่แชร์บนโมดูลก็เพียงพอสำหรับเก็บค่าที่ปรับได้ หน้าถัดไปจะเพิ่ม key เพิ่มเติม ตอนนี้มีแค่หนึ่ง:

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

10.5.1. GET เพื่ออ่าน POST เพื่อเขียน

route คู่หนึ่ง — 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 คืนค่า body ที่แยกวิเคราะห์เป็น JSON หรือ None หาก Content-Type ไม่ใช่ application/json handler ของ post ตรวจสอบทุกโหมดความล้มเหลว — key หาย, ประเภทผิด, ค่าเกินขอบเขต — และหยุดด้วย microdot.abort() ซึ่ง raise microdot.HTTPException เพื่อลัด handler ด้วยสถานะและข้อความที่กำหนด

10.5.2. GET, POST, PUT, DELETE

get() และ post() คือสองตัวที่เราจะใช้มากที่สุด put() และ delete() มีไว้สำหรับกรณีที่ปฏิบัติตาม REST convention — PUT /events/42 เพื่อแทนที่ event 42, DELETE /events/42 เพื่อลบออก handler ส่วนที่เหลือเหมือนกัน

10.5.3. การอ่าน query string และ form

แดชบอร์ดส่ง JSON ดังนั้น request.json คือสิ่งที่เราต้องการ อีกสองวิธีที่กล้องอาจรับข้อมูล:

  • args — query string ?foo=1&bar=2 กลายเป็น microdot.MultiDict ที่อ่านได้ด้วย request.args.get('foo')

  • form — HTML form ที่ส่งเป็น application/x-www-form-urlencoded ใช้ประเภท MultiDict เดียวกัน

MultiDict ทำงานเหมือน dict แต่ให้ key หนึ่งรองรับหลายค่าได้ (?tag=cat&tag=dog คือค่า tag สองค่า) ดู microdot.MultiDict สำหรับ API ครบถ้วน

10.5.4. URL segment แบบ dynamic

path ของ route สามารถประกาศ placeholder ที่มีประเภทกำกับ ซึ่ง microdot จะส่งไปยัง handler เป็นอาร์กิวเมนต์เพิ่มเติม:

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

converter ที่รองรับคือ <int:>, <re:> สำหรับ regex แบบกำหนดเอง, <path:> สำหรับ segment ที่มี slash ได้ และค่าเริ่มต้น (ไม่มี prefix) สำหรับ "จับคู่อะไรก็ได้จนถึง slash ถัดไป" <int:event_id> รับ /events/42 และปฏิเสธ /events/abc — การปฏิเสธกลายเป็น 404 โดยไม่รัน handler

10.5.5. Custom error response

404 ค่าเริ่มต้นที่ microdot ส่งคือ Not found ธรรมดา แดชบอร์ดคาดหวัง JSON สำหรับทุก response ดังนั้นให้ override handler ของ 404 ให้คืนค่า JSON ด้วย:

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

errorhandler() รับทั้ง status code (จับทุก error ที่มีสถานะนั้น) หรือ exception class (จับทุก handler ที่ raise exception นั้น) tuple แบบ (body, status) ลัด response โดยไม่ต้องสร้าง Response

กล้องตอนนี้เปิดเผยสถานะและรับการแก้ไขได้แล้ว