أشارككم في هذا الموضوع أهم الخطوات اللازمة لبناء واجهة برمجة تطبيقات API قوية وموثوقة يمكن للمطورين الاعتماد عليها لبناء تطبيقاتهم الخاصة.
سأستخدم إطار عمل Flask لبناء الواجهة البرمجية وسأوفر من خلالها بيانات عن أبرز الأقوام الواردة في القرآن الكريم.
هيكلة الواجهة البرمجية: RESTful
اعتمدت في تصميم الواجهة البرمجية API على مبادئ RESTful. والموارد الأساسية التي توفرها هي الأقوام qawms و الآيات verses، ونقاط الوصول endpoints هي:
GET /qawms: تعيد قائمة تفصيلية بكل الأقوام
<GET /qawms/<int:qawm_id: تعيد تفاصيل قوم بعينهم
GET /verses: تعيد قائمة بكل الآيات التي ذكرت أقوام
GET /qawms/<int:qawm_id>/verses: تعيد الآيات التي ذكرت قوم محددين
تنسيق البيانات JSON
تقدم الواجهة البرمجية البيانات بتنسيق JSON وفق الهيكيلة التالية:
{
"qawms": [
{
"id": 1,
"name": "المؤتفكة",
"type": "قوم",
"description": "المؤتفكة أو المؤتفكات هم قرى قوم لوط...",
"references": ["ابن كثير", "ابن عاشور"]
}
],
"verses": [
{
"id": 1,
"qawm_id": 1,
"verse_text": "وَالْمُؤْتَفِكَةَ أَهْوَى",
"verse_surah": "النجم",
"verse_ayah": 53
}
]
}
التطبيق العملي
بعد أن حددت هيكلة البيانات التي ستوفرها الواجهة ونقاط وصولها، بدأت مرحلة إنشاء تطبيق Flask ليوفرها. للسهولة خرنت البيانات في ملف باسم data.py بشكل قوائم من القواميس dictionaries، ويمكن كذلك جعل الواجهة البرمجية تتفاعل مع قواعد بيانات لجلب البيانات وتخزينها.
بعدها أنشأت الملف الرئيسي للتطبيق باسم app.py، وفعلت آلية مشاركة الموارد بين النطاقات CORS للسماح لأي نطاق بالوصول للواجهة البرمجية، ثم عرفت نقاط الوصول endpoints لجلب بيانات الأقوام والآيات:
from flask import Flask, jsonify, request
from flask_cors import CORS
from data import qawms_data, verses_data # البيانات من ملف data.py
from functools import wraps
app = Flask(__name__)
CORS(app) # تفعيل CORS
# نقطة جلب كل الأقوام
@app.route('/qawms', methods=['GET'])
def get_qawms():
return jsonify({"qawms": qawms_data})
# نقطة جلب قوم محدد
@app.route('/qawms/<int:qawm_id>', methods=['GET'])
def get_qawm(qawm_id):
qawm = next((q for q in qawms_data if q["id"] == qawm_id), None)
if qawm:
return jsonify(qawm)
return jsonify({"error": "Qawm not found"}), 404
# ... بنفس الطريقة عرفت نقاط الوصول الأخرى للآيات
تحسين أداء الواجهة من خلال الكاش Caching
لتحسين سرعة استجابة الواجهة البرمجية وتقليل الضغط على الخادم، استخدمت التخزين المؤقت في الذاكرة In-Memory Cache.
فكما يظهر في الكود التالي، يعمل المزخرف cached@ على تخزين نتيجة أول طلب يرسل لأي نقطة endpoint مفعّل عليها الكاش.
عند أول استدعاء، تُنفّذ الدالة وتُخزَّن النتيجة في الذاكرة مع الطابع الزمني. وعند تكرار الطلب لنفس المسار خلال مدة الصلاحية المحددة timeout، تُعاد النتيجة من الذاكرة مباشرة دون إعادة تنفيذ العملية.
import hashlib
from datetime import datetime, timezone
cache = {} # قاموس لتخزين الكاش
def cached(timeout=60):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# إنشاء مفتاح فريد للطلب بناء على المسار ومعلمات الاستعلام
cache_key = hashlib.md5((request.path + str(request.args)).encode('utf-8')).hexdigest()
now = datetime.now(timezone.utc)
if cache_key in cache:
data, timestamp = cache[cache_key]
# إذا كان الكاش صالح (لم تنته صلاحيته)
if (now - timestamp).total_seconds() < timeout:
return jsonify(data) # إرجاع البيانات من الكاش
# إذا لم يكن في الكاش أو انتهت صلاحيته، نفذ الدالة وخزن النتيجة
response = f(*args, **kwargs)
cache[cache_key] = (response.json, now)
return response
return decorated_function
return decorator
# مثال على استخدام الكاش في نقطة وصول
@app.route('/qawms', methods=['GET'])
@cached(timeout=300) # تخزين الاستجابة لمدة 300 ثانية
def get_qawms():
return jsonify({"qawms": qawms_data})
بهذا الأسلوب، ينخفض وقت الاستجابة بشكل ملحوظ، ويفّ الضغط على الخادم خصوصًا في الطلبات المتكررة أو المكثفة.
تأمين الواجهة البرمجية API
تأمين الواجهة أمر ضروري لحماية البيانات والموارد من الاستخدام غير المصرح به، ويمكن تحقيق ذلك من خلال:
استخدام المفاتيح API Keys
تستخدم مفاتيح الواجهة البرمجية كوسيلة بسيطة وآمنة للمصادقة وتحديد هوية التطبيقات أو المستخدمين الذين يتصلون بالواجهة البرمجية.
في الكود المرفق، يعمل المزخرف require_api_key@ على التحقق من وجود مفتاح صالح في رأس الطلب X-API-Key. عند إرسال طلب إلى أي endpoint محمية، يجب أن يحتوي رأس الطلب على مفتاح API مطابق لأحد المفاتيح المخزّنة في القاموس API_KEYS.
إذا كان المفتاح مفقودًا أو غير صالح، يرفض الخادم الطلب مباشرة ويعيد رمز الحالة 401 للدلالة على فشل المصادقة.
API_KEYS = {
"your_super_secret_api_key_1": {"owner": "DeveloperA"},
"your_super_secret_api_key_2": {"owner": "DeveloperB"}
}
def require_api_key(f):
@wraps(f)
def decorated_function(*args, **kwargs):
api_key = request.headers.get('X-API-Key') # جلب المفتاح من رأس الطلب
if not api_key or api_key not in API_KEYS:
return jsonify({"error": "Unauthorized: Invalid or missing API Key"}), 401
return f(*args, **kwargs)
return decorated_function
# مثال على استخدام حماية مفتاح الـ API
@app.route('/qawms', methods=['GET'])
@require_api_key # يتطلب مفتاح API للوصول
@cached(timeout=300)
def get_qawms():
return jsonify({"qawms": qawms_data})
بهذا الأسلوب، يمكن التحكم في من يسمح له بالوصول إلى البيانات، ومنع الاستخدام غير المصرح به للواجهة البرمجية.
تحديد معدل الطلبات Rate Limiting
تحديد معدل الطلبات من الإجراءات الأساسية أيضًا لتأمين الواجهة البرمجية، إذ يمنع المستخدمين أو التطبيقات من إرسال عدد مفرط من الطلبات خلال فترة قصيرة، ويحمي الخادم من هجمات DDoS ويحافظ على استقرار الأداء.
في الكود المرفق، ينفذ المزخرف rate_limit@ آلية تقييد الطلبات بناءً على عنوان الـIP. ويسمح بإجراء خمسة طلبات فقط لكل عنوان IP خلال 60 ثانية.
إذا تجاوز المستخدم هذا الحد، يرفض الخادم الطلب فورًا ويعيد رمز الحالة 429، مع رسالة توضح أن عليه الانتظار قبل المحاولة مجددًا.
بهذه الطريقة يمكن حماية الواجهة من الإغراق بالطلبات، وضمان توزيع عادل للموارد بين المستخدمين.
rate_limit_counts = {}
RATE_LIMIT = 5 # 5 طلبات كحد أقصى
RATE_LIMIT_WINDOW = 60 # في غضون 60 ثانية
def rate_limit(f):
@wraps(f)
def decorated_function(*args, **kwargs):
ip_address = request.remote_addr # الحصول على عنوان IP للمستخدم
now = datetime.now(timezone.utc)
if ip_address not in rate_limit_counts:
rate_limit_counts[ip_address] = []
# إزالة الطلبات القديمة التي تجاوزت الحد
rate_limit_counts[ip_address] = [
t for t in rate_limit_counts[ip_address]
if (now - t).total_seconds() < RATE_LIMIT_WINDOW
]
# إذا تجاوز عدد الطلبات الحد المسموح به
if len(rate_limit_counts[ip_address]) >= RATE_LIMIT:
return jsonify({"error": f"Rate limit exceeded. Try again in {RATE_LIMIT_WINDOW} seconds."}), 429
rate_limit_counts[ip_address].append(now) # إضافة الطلب الحالي
return f(*args, **kwargs)
return decorated_function
# مثال على تحديد معدل الطلبات
@app.route('/qawms', methods=['GET'])
@require_api_key
@rate_limit # تطبيق تحديد معدل الطلبات
@cached(timeout=300)
def get_qawms():
return jsonify({"qawms": qawms_data})
استخدام JWT
لا تعتمد الواجهة الحالية نظام JWT، لكني أود الإشارة له لكونه واحدًا من أهم أساليب المصادقة في تطبيقات الويب والجوال الحديثة.
تعتمد فكرته على أن المستخدم، بعد تسجيل الدخول بنجاح، يحصل على رمز مميز Token يحتوي على بيانات تعريفه بشكل آمن ومشفر.
يُرسل هذا الرمز مع كل طلب لاحق إلى الواجهة البرمجية لإثبات هوية المستخدم دون الحاجة لإعادة إدخال بيانات الاعتماد في كل مرة.
يساعد هذا النظام في بناء جلسات آمنة وسريعة، خصوصًا في التطبيقات التي تتعامل مع مستخدمين مسجلين أو صلاحيات متعددة.
نشر الواجهة البرمجية
لجعل الواجهة البرمجية التي نفذتها متاحة للاستخدام من قبل الجميع، سأحتاج لنشرها على خدمات استضافة سحابية، اخترت خدمة Render التي تقدم خطة مجانية.
قبل النشر، يجب تجهيز المشروع بخطوات أساسية:
`web: gunicorn app:app`
إعداد التطبيق للإنتاج:
التأكد من أن التطبيق لا يعمل في وضع التصحيح (debug mode) داخل ملف app.py عبر السطر:
app.run(debug=False)
إذ يتولى gunicorn تشغيل التطبيق في بيئة الإنتاج.
رفع المشروع إلى GitHub
لإنشاء مستودع يحتوي على الكود وجميع ملفاته.
النشر عبر Render: بعد تسجيل الدخول إلى حساب Render، أنشأت خدمة جديدة Web Service

ثم ربطتها بمستودع المشروع في GitHub، مع ضبط الإعدادات كما يلي:
Runtime: Python 3
Build Command: pip install -r requirements.txt
Start Command: gunicorn app:app
وحددت الخطة المجانية للتجربة، ثم انتظرت عملية النشر وتوفير رابط عام يمكن استخدامه للوصول إلى الواجهة البرمجية واستهلاكها من قبل المطورين.

اختبار الواجهة البرمجية
يمكن اختبار طلبات الواجهة بعدة طرق أسهلها من خلال curl كما في الأمثلة التالية:
لعرض كل الأقوام نكتب الطلب على النحو التالي:
curl -H "X-API-Key: your_super_secret_api_key_1" https://qawm-api.onrender.com/qawms
ولعرض الآيات التي للقوم الذي له المعرف 1 نكتا:
curl -H "X-API-Key: your_super_secret_api_key_1" https://qawm-api.onrender.com/qawms/1/verses
بناء تطبيق يستخدم الواجهة البرمجية

أخيرًا للتحقق من عمل الواجهة وإظهار كيفية الاستفادة منها طورت تطبيق ويب يربط بين الواجهة البرمجية وواجهة أمامية بسيطة يمكن استعراضه بشكل مباشرة على هذا الرابط
ملاحظة: قد تلاحظ تأخر التطبيق في الاستجابة عند أول تحميل لأن الواجهة البرمجية مستضافة على خطة مجانية في Render، والتي تقوم بإيقاف الخادم مؤقتًا عند عدم النشاط لتوفير الموارد. وعند فتح التطبيق من جديد، تحتاج المنصة بضع ثوانٍ لإعادة تشغيل الخادم قبل إرسال أول استجابة.
يتضمن التطبيق 4 ملفات:
index.html: يحدد هيكل الصفحة.
style.css: ينسق الصفحة، مع تصميم متجاوب يناسب الأجهزة المحمولة.
api.js: يتولى التواصل مع الواجهة البرمجية باستخدام المفتاح ويجلب بيانات الأقوام:
// جلب البيانات
async function fetchQawms() {
const res = await fetch('https://qawm-api.onrender.com/qawms', {
headers: { 'X-API-Key': 'your_api_key' }
});
return (await res.json()).qawms || [];
}
main.js: يعالج البيانات التي تعيدها الواجهة ويعرضها في الصفحة.
// عرض البيانات
async function showQawms() {
const data = await fetchQawms();
document.getElementById('contentArea').innerHTML = data.map(q =>
`<div class="qawm-card">
<h3>${q.name}</h3>
<p>${q.description}</p>
</div>`).join('');
}
document.addEventListener('DOMContentLoaded', showQawms);
الكود البرمجي الكامل
كانت تلك أبرز الخطوات لتطوير الواجهة ونشرها مع تأمينها بمفتاح API وكاش لتحسين الأداء إلى جانب ربطها بواجهة أمامية بسيطة لعرض البيانات بعض البيانات بشكل منظم.
يمكن الحصول على كامل كود الواجهة البرمجية من مستودع QawmAPI على GitHub
كما يمكن الحصول على كود الواجهة الأمامية من خلال المستودع Qawm-frontend
ختامًا
بهذا أكون أنهيت خطوات تطوير واجهة API بسيطة مفتوحة المصدر باستخدام Flask وتطبيق ويب بسيط يستهلك هذه الواجهة، ووضحت طرق مختلفة لتحسين أدائها وتأمينها ونشرها واستخدامها في تطبيق خارجي.
هل سبق لك تطوير واجهة برمجية تخدم التطبيقات القرآنية، وما هي أفضل المعايير التي توليها الأولوية عند بناء واجهاتك البرمجية؟ هل تركز أكثر على الأداء، أم على الأمان، أم على سهولة التكامل والتوثيق؟