من مشروع Python صغير إلى خدمة سحابية مُدارة: تحويل Flask إلى FastAPI + ASGI ونشر عملي
مقدمة — لماذا التحويل من Flask إلى FastAPI؟
إذا بدأت بمشروع Python صغير باستخدام Flask ثم احتجت لميزات أعلى في الأداء، واجهات توثيق أتوماتيكية، أو دعم أفضل للبرمجة غير المتزامنة (async)، فـ FastAPI خيار مناسب. FastAPI مُبني على Starlette وASGI، ويُسهل كتابة مسارات سريعة وآمنة مع استنتاج الأنواع (type hints) ووثائق OpenAPI تلقائية.
في هذا الدليل العملي ستتعلم خطوات عملية: كيف تُحوّل أجزاء من تطبيق Flask إلى FastAPI تدريجيًا أو دفعة واحدة، كيفية تشغيل التطبيق باستخدام خوادم ASGI مثل uvicorn أو عبر مدير عمليات مثل gunicorn مع عمال Uvicorn، وكيفية نشر الخدمة على VPS مع Nginx وLet's Encrypt أو تعبئتها داخل Docker للنشر السحابي.
ملاحظة تقنية أساسية: FastAPI يعمل على ASGI. لتشغيله في بيئة إنتاجية يُنصح باستخدام Uvicorn (ASGI) مع آليات إدارة عمال العمليات أو Gunicorn مع عامل Uvicorn حسب حاجتك.
الخطوة 1 — استراتيجيات الهجرة من Flask إلى FastAPI
قبل البدء عمليًا، قرر استراتيجية الهجرة الأنسب لمشروعك:
- هجرة تدريجية (مُوصى بها للأنظمة الحية): أبقِ تطبيق Flask قيد التشغيل وادخل FastAPI على مسار فرعي مثل
/api/v2/. استخدمWSGIMiddlewareأو reverse proxy لإيصال الطلبات إلى التطبيق المناسب. هذه الطريقة تخفض المخاطر وتمكّن فِرقًا مختلفة من العمل بالتوازي. - إعادة كتابة كلية: مناسب للمشروعات الصغيرة أو عند الحاجة إلى تنظيف معماري شامل. يتطلب اختبارًا مكثفًا ويُفضل تنفيذ نسخة احتياطية أو مسار معاودة تشغيل سريع.
تحويل مثال بسيط (Flask → FastAPI)
# Flask (app_flask.py)
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/items/')
def get_item(id):
return jsonify({"id": id, "name": "item"})
# FastAPI (app_fastapi.py)
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
id: int
name: str
@app.get('/items/{id}', response_model=Item)
async def get_item(id: int):
return Item(id=id, name="item")
ملاحظات عملية: استعمل async def عندما تحتاج لعمليات I/O غير متزامنة (قواعد بيانات غير متزامنة، استدعاءات HTTP غير متزامنة). إذا كان كود Flask يعتمد على API مُزامن قد تترك الدالة غير متزامنة وتُعرّفها كدالة عادية في FastAPI (يعمل ذلك أيضاً)، لكن لتحصيل أفضل أداء استفد من التحويل إلى async حيث يُمكن.
الخطوة 2 — تشغيل FastAPI في الإنتاج: Uvicorn وGunicorn وبدائلهم
خيارات شائعة لتشغيل FastAPI في بيئة إنتاجية:
- Uvicorn بمفرده ـ مناسب للتطبيقات البسيطة. Uvicorn يدعم تشغيل عمال عبر الخيار
--workers، لكن--reloadلا يعمل مع--workers. - Gunicorn + Uvicorn workers ـ نمط مألوف يوفر إمكانيات إدارة عمليات متقدّمة (restart، graceful reload)، وتُستخدم فئة العامل
uvicorn.workers.UvicornWorkerأو الحزمة الموصى بهاuvicorn-worker. مثال تشغيل:
# تشغيل مباشر بـ Uvicorn (مثال إنتاجي بسيط)
uvicorn app_fastapi:app --host 0.0.0.0 --port 8000 --workers 4
# تشغيل مع Gunicorn (تحكم أفضل بالعمليات)
gunicorn app_fastapi:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
ملاحظة مهمة: التوصية التقليدية كانت استخدام Gunicorn لإدارة العمال بينما Uvicorn يقدم أداء ASGI. منذ تحديثات Uvicorn تمت إضافة إدارة العمال داخليًا مما يجعل استخدام Uvicorn لوحده خيارًا عمليًا في كثير من الحالات، لكن بعض سيناريوهات الإدارة المتقدمة تبقى سببًا لاستعمال Gunicorn. اختر ما يناسب حاجتك بعد تجربة بسيطة.
نقطة مهمة حول صورة Docker أساسية: صورة tiangolo/uvicorn-gunicorn-fastapi كانت شائعة لسنوات، لكن راجع المستودع الرسمي لأن بعض التوصيات والصور تغيّرت أو تم تحذيرها للترقية. عند استخدام Docker، استخدم صورًا محدثة واقرأ توجيهات الصيانة.
الخطوة 3 — نشر عملي على VPS (Ubuntu) باستخدام systemd وNginx وLet's Encrypt
فيما يلي مثال عملي مختصر لنشر تطبيق FastAPI على خادم Ubuntu مشغّل على VPS (مثال عملي مع Nginx كموازن عكسي، systemd لإدارة الخدمة، وLet's Encrypt لتمكين HTTPS).
1) ملف systemd لخدمة FastAPI
[Unit]
Description=FastAPI app (uvicorn)
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
Environment="PATH=/opt/myapp/venv/bin"
ExecStart=/opt/myapp/venv/bin/uvicorn app_fastapi:app --host 127.0.0.1 --port 8000 --workers 4
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
بعد إنشاء الملف شغّل:
sudo systemctl daemon-reload && sudo systemctl enable --now myapp.service
2) إعداد Nginx كموازن عكسي (نمطي)
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
استخدم Certbot (Let's Encrypt) لتمكين HTTPS: sudo certbot --nginx -d api.example.com. تأكد من فتح المنافذ 80 و443 في جدار الحماية. وثّق أن Certbot يضيف ضبطًا آمنًا لـ TLS وعمليات التجديد الأوتوماتيكي.
بدائل: Docker وDocker Compose
إن أردت حزم التطبيق داخل حاوية، استخدم Dockerfile بسيط ثم Docker Compose مع Traefik أو Nginx Proxy Manager للتوجيه وHTTPS التلقائي. للحِجَم الصغيرة يسهّل ذلك الانتقال إلى موفري Cloud مثل DigitalOcean App Platform أو AWS ECS / Cloud Run.
خاتمة ونصائح عملية
- ابدأ بالهجرة التدريجية إن كان المشروع حيًا لتقليل المخاطر.
- اختبر الأداء قبل/بعد التحويل باستخدام أدوات قياس (wrk, locust) وراقب الذاكرة والمقاييس.
- حافظ على أسرار التكوين في متغيرات البيئة أو مدير أسرار (Vault) وليس في الشيفرة.
- اضبط التجديد التلقائي لشهادات Let's Encrypt وتحقق من السجلات (logs) دورياً.
إذا رغبت، أستطيع: 1) تحويل مثال Flask صغير ترسله إليّ مباشرةً إلى FastAPI متكامل، أو 2) توليد ملفات systemd, nginx, وDockerfile مخصصة لمشروعك. أخبرني بطبيعة مشروعك (قواعد بيانات، استدعاءات خارجية، مزود السحابة) وسأجهّز لك سيناريو نشر مفصّل.