دورة FastAPI: تعلّم بناء واجهات API بسرعة باستخدام بايثون
ما هي FastAPI ولماذا تحظى بهذه الشعبية؟
تُعد FastAPI إطار عمل حديثاً وسريعاً لبناء واجهات API باستخدام لغة Python. وقد صُمّم ليمنح المطورين تجربة تطوير مرنة، مع أداء مرتفع وسهولة واضحة في كتابة الشيفرة وتوثيقها واختبارها.
تكمن قوة FastAPI في أنها تجمع بين عدة مزايا مهمة:
- سهولة البدء حتى للمطور الذي يملك أساسيات جيدة في
Python. - توثيق تلقائي جاهز عبر واجهات مثل
Swagger UI. - دعم ممتاز لتحديد أنواع البيانات والتحقق منها.
- أداء عالٍ مناسب للتطبيقات الحديثة والخدمات الخلفية.
إذا كنت ترغب في تطوير واجهات برمجية بسرعة ومنهجية واضحة، فإن FastAPI خيار عملي وقوي.

ماذا ستتعلم في هذه الدورة التقنية؟
يركّز هذا الدرس التمهيدي على أساسيات العمل مع FastAPI، ويغطي المحاور التالية:
- تثبيت
FastAPIوتشغيل المشروع لأول مرة. - إنشاء أول واجهة
API. - التعامل مع
Path Parameters. - استخدام
Query Parameters. - دمج مسارات الطلب مع معاملات الاستعلام.
- إرسال البيانات عبر
Request Body. - استخدام العمليات الأساسية:
GETوPOSTوPUTوDELETE.
المتطلبات الأساسية قبل البدء
قبل البدء في تعلّم FastAPI، يُفضَّل أن يكون لديك:
- معرفة أساسية بلغة
Python. - إصدار
Python 3.6أو أحدث مثبت على جهازك. - محرر شيفرة مثل
Visual Studio Code. - معرفة بسيطة بكيفية استخدام الطرفية أو سطر الأوامر.
تثبيت FastAPI وتشغيل الخادم
عملية التثبيت بسيطة جداً، لأن FastAPI تُثبت عبر مدير الحزم pip. كذلك تحتاج إلى أداة uvicorn لتشغيل الخادم المحلي.
pip install fastapi uvicorn
يمكنك أيضاً استخدام أوامر بديلة بحسب نظام التشغيل أو إعدادات بيئتك، مثل:
python -m pip install fastapi
pip install uvicorn
تكمن أهمية uvicorn في أنه يشغّل تطبيق ASGI، وهو ما تحتاجه FastAPI لعرض الواجهة البرمجية عبر المتصفح أو أدوات الاختبار.
إنشاء أول تطبيق باستخدام FastAPI
بعد تثبيت الحزم، أنشئ ملفاً باسم myapi.py ثم أضف الشيفرة التالية:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def index():
return {"name": "first data"}
في هذا المثال:
- قمنا باستيراد الكائن
FastAPI. - أنشأنا نسخة من التطبيق داخل المتغير
app. - أضفنا مساراً رئيسياً باستخدام
@app.get("/"). - أعدنا استجابة بصيغة تشبه
JSON.
تشغيل التطبيق محلياً
لتشغيل المشروع، استخدم الأمر التالي:
uvicorn myapi:app --reload
هذا الأمر يعني:
myapi: اسم الملف دون الامتداد.py.app: اسم المتغير الذي يحتوي على تطبيقFastAPI.--reload: لإعادة تشغيل الخادم تلقائياً عند تعديل الشيفرة.
بعد التشغيل، افتح المتصفح على العنوان المحلي الذي يظهر في الطرفية، وغالباً سيكون http://127.0.0.1:8000.
التوثيق التلقائي في FastAPI
من أبرز ميزات FastAPI أنها تنشئ توثيقاً تفاعلياً تلقائياً. يكفي أن تفتح الرابط:
http://127.0.0.1:8000/docs
ستظهر لك واجهة Swagger UI التي تسمح لك بما يلي:
- استعراض جميع المسارات المتاحة.
- معرفة نوع كل طلب مثل
GETأوPOST. - اختبار الطلبات مباشرة من المتصفح.
- عرض الاستجابات وأكواد الحالة بسهولة.
هذه الميزة تختصر وقتاً كبيراً في الاختبار والتوثيق، وهي مفيدة جداً أثناء التطوير والعمل الجماعي.
فهم مفهوم Endpoint في واجهات API
يشير مصطلح Endpoint إلى نقطة وصول محددة داخل الواجهة البرمجية. وغالباً ما تكون جزءاً من الرابط يُستخدم لتنفيذ وظيفة معينة، مثل:
- جلب بيانات مستخدم.
- إنشاء سجل جديد.
- تعديل عنصر موجود.
- حذف مورد من قاعدة البيانات.
على سبيل المثال، في رابط مثل /get-student/1 فإن الجزء /get-student/1 يمثل نقطة وصول مخصصة لاسترجاع بيانات طالب معيّن.
العمليات الأساسية في REST API
عند بناء واجهات برمجية، ستتعامل كثيراً مع العمليات التالية:
GET: لجلب البيانات أو عرضها.POST: لإنشاء مورد جديد.PUT: لتحديث مورد موجود.DELETE: لحذف مورد محدد.
هذه العمليات تشكّل الأساس العملي لمعظم تطبيقات API الحديثة.
استخدام Path Parameters لاسترجاع بيانات ديناميكية
لنفترض أن لدينا قاموساً بسيطاً يمثل بيانات الطلاب:
from fastapi import FastAPI, Path
app = FastAPI()
students = {
1: {
"name": "John",
"age": 17,
"class": "year 12"
}
}
@app.get("/get-student/{student_id}")
def get_student(student_id: int):
return students[student_id]
هنا استخدمنا {student_id} داخل الرابط، وهذا يعني أن القيمة ستُمرر من الرابط مباشرة. فإذا طلبت الرابط /get-student/1 فستحصل على بيانات الطالب ذي المعرف 1.
إضافة وصف وقيود على قيمة المعرف
يمكنك تحسين جودة الواجهة بإضافة وصف ومعايير تحقق:
@app.get("/get-student/{student_id}")
def get_student(
student_id: int = Path(None, description="المعرّف الخاص بالطالب", gt=0, lt=3)
):
return students[student_id]
في هذا المثال:
description: يشرح وظيفة الحقل داخل التوثيق.gt=0: يشترط أن تكون القيمة أكبر من0.lt=3: يشترط أن تكون القيمة أقل من3.
هذه التفاصيل تجعل التوثيق أوضح، وتمنع إدخال قيم غير منطقية منذ البداية.
استخدام Query Parameters للبحث والتصفية
تُستخدم Query Parameters عندما تريد تمرير بيانات إضافية بعد علامة الاستفهام داخل الرابط، مثل:
/get-by-name?name=John
مثال عملي:
@app.get("/get-by-name")
def get_student(*, name: str):
for student_id in students:
if students[student_id]["name"] == name:
return students[student_id]
return {"Data": "Not found"}
في هذا المسار، لا نمرر المعرف داخل الرابط نفسه، بل نستخدم المعامل name للاستعلام عن الطالب بالاسم.
جعل معاملات الاستعلام اختيارية
يمكن جعل الحقل اختيارياً باستخدام Optional:
from typing import Optional
@app.get("/get-by-name")
def get_student(*, name: Optional[str] = None):
for student_id in students:
if students[student_id]["name"] == name:
return students[student_id]
return {"Data": "Not found"}
هذا الأسلوب أنظف من الناحية البرمجية، كما يوضّح في التوثيق أن القيمة ليست إلزامية.
الفرق بين Path Parameters وQuery Parameters
| النوع | مكانه في الرابط | الاستخدام الشائع |
|---|---|---|
Path Parameter |
داخل المسار نفسه | تحديد مورد بعينه مثل معرف الطالب |
Query Parameter |
بعد علامة ? |
البحث، التصفية، الفرز، الخيارات الإضافية |
عملياً، إذا كنت تريد الوصول إلى عنصر محدد بهوية واضحة، فاستخدم Path Parameter. أما إذا كنت تريد البحث أو التصفية، فالأفضل استخدام Query Parameter.
دمج Path وQuery في مسار واحد
في بعض الحالات قد تحتاج إلى استخدام النوعين معاً داخل نفس الطلب. مثال على ذلك:
@app.get("/get-student/{student_id}")
def get_student(*, student_id: int, name: Optional[str] = None):
return {"student_id": student_id, "name": name}
هذا الدمج يكون مفيداً عندما تريد تحديد مورد رئيسي باستخدام المعرّف، مع تمرير خيار إضافي مثل الاسم أو نوع العرض أو حالة التصفية.
التعامل مع Request Body وطلب POST
عند إنشاء سجل جديد، لا يكفي عادةً تمرير المعرف فقط، بل تحتاج إلى إرسال بيانات الكائن نفسه داخل جسم الطلب Request Body. وهنا تظهر أهمية نماذج Pydantic.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
students = {}
class Student(BaseModel):
name: str
age: int
year: str
@app.post("/create-student/{student_id}")
def create_student(student_id: int, student: Student):
if student_id in students:
return {"Error": "Student exists"}
students[student_id] = student.dict()
return students[student_id]
في هذا المثال:
- أنشأنا نموذجاً باسم
Student. - حدّدنا الحقول المطلوبة وأنواعها.
- استخدمنا
POSTلإنشاء طالب جديد. - تحققنا أولاً من عدم وجود الطالب مسبقاً.
ميزة هذا الأسلوب أن FastAPI تتحقق تلقائياً من صحة البيانات قبل تنفيذ المنطق البرمجي.
تحديث البيانات باستخدام PUT
لتحديث البيانات الموجودة، نستخدم عادة الطلب PUT. لكن توجد نقطة مهمة: المستخدم قد لا يرغب في تعديل جميع الحقول، بل جزءاً منها فقط. لذلك من الأفضل إنشاء نموذج منفصل للحقول الاختيارية.
from typing import Optional
from pydantic import BaseModel
class UpdateStudent(BaseModel):
name: Optional[str] = None
age: Optional[int] = None
year: Optional[str] = None
ثم نستخدمه داخل مسار التحديث:
@app.put("/update-student/{student_id}")
def update_student(student_id: int, student: UpdateStudent):
if student_id not in students:
return {"Error": "Student does not exist"}
if student.name is not None:
students[student_id]["name"] = student.name
if student.age is not None:
students[student_id]["age"] = student.age
if student.year is not None:
students[student_id]["year"] = student.year
return students[student_id]
لماذا هذا الأسلوب مهم؟
لو استخدمت نموذجاً يفرض جميع الحقول، فسيصبح المستخدم مضطراً لإرسال كل البيانات في كل مرة، حتى لو أراد تعديل قيمة واحدة فقط. أما النموذج الاختياري فيسمح بتحديث جزئي من دون الكتابة فوق القيم الأصلية بـ None.
وهذا يعد سلوكاً أفضل من ناحية تجربة المطور، كما يقلل الأخطاء المنطقية داخل التطبيق.
حذف البيانات باستخدام DELETE
لحذف سجل معين، يمكنك إنشاء مسار بسيط يعتمد على معرّف العنصر:
@app.delete("/delete-student/{student_id}")
def delete_student(student_id: int):
if student_id not in students:
return {"Error": "Student does not exist"}
del students[student_id]
return {"Message": "Student deleted successfully"}
هذا المسار ينفّذ خطوتين أساسيتين:
- التحقق من وجود الطالب.
- حذف السجل ثم إرجاع رسالة نجاح.
ورغم بساطة المثال، فإنه يعكس منطق الحذف المستخدم في معظم تطبيقات CRUD العملية.
أفضل الممارسات عند تعلّم FastAPI
- استخدم نماذج
Pydanticدائماً لتنظيم البيانات والتحقق منها. - افصل بين نماذج الإنشاء ونماذج التحديث.
- أضف أوصافاً للمعاملات باستخدام
Path()ووسائل التحقق الأخرى. - اختبر جميع المسارات عبر صفحة
/docsأثناء التطوير. - لا تعتمد على القواميس داخل الذاكرة في المشاريع الحقيقية، بل استخدم قاعدة بيانات مناسبة.
متى تكون FastAPI خياراً مناسباً؟
تكون FastAPI مناسبة جداً في الحالات التالية:
- بناء خدمات خلفية سريعة لواجهات الويب أو تطبيقات الجوال.
- إنشاء
REST APIsواضحة وقابلة للتوسع. - تطوير أدوات داخلية للشركات والفرق التقنية.
- إنشاء نماذج أولية بسرعة قبل الانتقال إلى بيئات الإنتاج.
- المشاريع التي تتطلب توثيقاً تلقائياً واختبارات سريعة.
الخلاصة التقنية
تقدّم FastAPI مزيجاً ممتازاً من السرعة وسهولة التطوير وجودة التوثيق، وهو ما يجعلها إطاراً عملياً للغاية لبناء واجهات API حديثة باستخدام Python. من الناحية التقنية، أهم ما يميزها ليس فقط الأداء، بل قدرتها على فرض بنية نظيفة للبيانات عبر Pydantic، مع تقليل الأخطاء وتحسين تجربة المطور. إذا كنت تبدأ في عالم الواجهات البرمجية أو تبحث عن إطار خفيف واحترافي، فإن تعلّم FastAPI استثمار ذكي ومفيد على المدى الطويل.