10.5. واجهة برمجية للتحكم في الكاميرا¶
يحتاج المالك إلى ضبط حساسية كاشف الحركة من أي مكان -- فالرياح تُحرِّك الأشجار أكثر في الأيام العاصفة. وهذا يعني وجود مسارات تستطيع لوحة المعلومات قراءة الإعدادات الحالية منها وإرسال التغييرات إليها.
يكفي قاموس حالة صغير مُشترَك على مستوى الوحدة لحفظ المفاتيح القابلة للضبط. وتضيف الصفحات اللاحقة مزيدًا من المفاتيح إليه؛ أما الآن فهناك مفتاح واحد:
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، أو None إن لم يكن Content-Type هو application/json. ويمرّ معالج post على كل نمط فشل -- مفتاح مفقود، أو نوع خاطئ، أو قيمة خارج النطاق -- ثم ينسحب باستخدام 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-- نموذج HTML مُرسَل بصيغةapplication/x-www-form-urlencoded. وهو من نوعMultiDictنفسه.
إن MultiDict شبيه بالقاموس لكنه يسمح لمفتاح واحد بحمل قيم متعددة (إذ يكون ?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. استجابات الأخطاء المخصصة¶
إن استجابة 404 الافتراضية التي يرسلها microdot هي مجرد 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.
تكشف الكاميرا الآن حالتها وتقبل التعديلات.