
أصبح FastAPI هو الخيار الافتراضي لواجهات برمجة تطبيقات Python الجديدة، وذلك لسبب وجيه: مستندات OpenAPI التلقائية، ودعم غير متزامن حقيقي، وطلب التحقق من الصحة المدعوم من Pydantic الذي يكتشف المدخلات السيئة قبل أن تمس منطق عملك. ينشئ هذا البرنامج التعليمي واجهة REST API عاملة من مجلد فارغ إلى خدمة CRUD مدعومة بقاعدة البيانات مع بنية جاهزة للمصادقة.
📋 Table of Contents
جدول المحتويات
- إعداد المشروع
- طريقك الأول
- نماذج الطلب والاستجابة مع Pydantic
- إضافة قاعدة بيانات باستخدام SQLModel
- بناء نقاط نهاية CRUD كاملة
- معالجة الأخطاء
- المستندات التلقائية
- يعمل في الإنتاج
- الأسئلة الشائعة
إعداد المشروع
أنشئ بيئة افتراضية وقم بتثبيت الحزم الأساسية:
mkdir fastapi-todo && cd fastapi-todo
python3 -m venv venv
source venv/bin/activate
pip install fastapi uvicorn[standard] sqlmodel
uvicornهو خادم ASGI الذي يقوم بالفعل بتشغيل تطبيقك؛sqlmodelيجمع بين SQLAlchemy وPydantic لطبقة قاعدة بيانات تشارك النماذج مع مخططات API الخاصة بك.
طريقك الأول
إنشاءmain.py:
from fastapi import FastAPI
app = FastAPI(title="Todo API")
@app.get("/")
def read_root():
return {"message": "Todo API is running"}
قم بتشغيله مع التحديث السريع:
uvicorn main:app --reload
زيارةhttp://127.0.0.1:8000وسترى استجابة JSON. زيارة/docsولديك بالفعل واجهة مستخدم Swagger تفاعلية – تم إنشاؤها من توقيعات وظيفتك فقط.
نماذج الطلب والاستجابة مع Pydantic
بدلاً من التحقق يدوياًrequest.json()بالنسبة للحقول المفقودة، حدد نموذجًا واترك FastAPI يتحقق من صحة الأمر نيابةً عنك:
from pydantic import BaseModel
class TodoCreate(BaseModel):
title: str
done: bool = False
@app.post("/todos")
def create_todo(todo: TodoCreate):
return {"title": todo.title, "done": todo.done}
إرسال طلب مفقودtitleويقوم FastAPI بإرجاع خطأ منظم 422 تلقائيًا – لا حاجة إلى تعليمات برمجية إضافية. تعد طبقة التحقق هذه هي السبب الأكبر وراء ترحيل الفرق من Flask.
إضافة قاعدة بيانات باستخدام SQLModel
يتيح SQLModel لفئة واحدة أن تكون بمثابة جدول قاعدة البيانات ومخطط واجهة برمجة التطبيقات (API) الخاص بك:
from sqlmodel import SQLModel, Field, create_engine, Session
class Todo(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
title: str
done: bool = False
engine = create_engine("sqlite:///todos.db")
def init_db():
SQLModel.metadata.create_all(engine)
def get_session():
with Session(engine) as session:
yield session
اتصلinit_db()عند بدء التشغيل باستخدام معالج عمر FastAPI:
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db()
yield
app = FastAPI(title="Todo API", lifespan=lifespan)
بناء نقاط نهاية CRUD كاملة
مع وجود تبعية النموذج والجلسة، تكون عمليات CRUD الأربع قصيرة وسهلة القراءة:
from fastapi import Depends, HTTPException
from sqlmodel import select
@app.post("/todos", response_model=Todo)
def create_todo(todo: Todo, session: Session = Depends(get_session)):
session.add(todo)
session.commit()
session.refresh(todo)
return todo
@app.get("/todos", response_model=list[Todo])
def list_todos(session: Session = Depends(get_session)):
return session.exec(select(Todo)).all()
@app.get("/todos/{todo_id}", response_model=Todo)
def get_todo(todo_id: int, session: Session = Depends(get_session)):
todo = session.get(Todo, todo_id)
if not todo:
raise HTTPException(status_code=404, detail="Todo not found")
return todo
@app.put("/todos/{todo_id}", response_model=Todo)
def update_todo(todo_id: int, data: Todo, session: Session = Depends(get_session)):
todo = session.get(Todo, todo_id)
if not todo:
raise HTTPException(status_code=404, detail="Todo not found")
todo.title = data.title
todo.done = data.done
session.add(todo)
session.commit()
session.refresh(todo)
return todo
@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: int, session: Session = Depends(get_session)):
todo = session.get(Todo, todo_id)
if not todo:
raise HTTPException(status_code=404, detail="Todo not found")
session.delete(todo)
session.commit()
return {"ok": True}
إشعارDepends(get_session)— نظام حقن تبعية FastAPI. يعملget_sessionلكل طلب، قم بتسليم النتيجة إلى وظيفتك، ثم قم بتنظيفها بعد ذلك. يتغير نفس النمط إلى المصادقة، وتحديد المعدل، والصفحات دون تكرار النموذج المعياري في كل معالج.
معالجة الأخطاء
HTTPExceptionيغطي معظم الحالات، ولكن بالنسبة للأخطاء الخاصة بالمجال، قم بتسجيل معالج استثناء مخصص حتى تظل الاستجابات متسقة عبر واجهة برمجة التطبيقات:
from fastapi.responses import JSONResponse
from fastapi import Request
class TodoLimitError(Exception):
pass
@app.exception_handler(TodoLimitError)
def limit_handler(request: Request, exc: TodoLimitError):
return JSONResponse(status_code=400, content={"error": "todo limit reached"})
المستندات التلقائية
كل مسار كتبته موثق بالفعل في/docs(اختيال) و/redoc(ReDoc)، الذي تم إنشاؤه من نماذج Pydantic وتلميحات الكتابة. أضف أوصافًا باستخدام سلسلة مستندية أوField(description=...)وتظهر في المخطط الذي تم إنشاؤه تلقائيًا – لا يوجد OpenAPI YAML منفصل للمحافظة عليه يدويًا.
يعمل في الإنتاج
للإنتاج، قم بتشغيل Uvicorn خلف Gunicorn مع العديد من العمال، أو استخدم وضع Uvicorn متعدد العمال:
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
ضعه خلف Nginx أو موازن التحميل المُدار لإنهاء TLS، واستبدل SQLite بـ PostgreSQL عن طريق تغييرcreate_engineسلسلة الاتصال – لا تتغير واجهة برمجة تطبيقات SQLModel.
إذا كنت تقوم بإقران واجهة برمجة التطبيقات هذه بواجهة أمامية حديثة، فإنNext.js 15 ودليل PostgreSQLيغطي جانب العميل، وللتعرف على أساسيات المزامنة في JavaScript، راجعالمزامنة/الانتظار لدينا للغوص العميق.
الأسئلة الشائعة
هل FastAPI أسرع من Flask؟
إن دعم FastAPI غير المتزامن وأساس Starlette يجعله أسرع بشكل كبير في ظل التحميل المتزامن، خاصة بالنسبة لنقاط النهاية المرتبطة بالإدخال/الإخراج مثل مكالمات قاعدة البيانات أو طلبات واجهة برمجة التطبيقات الخارجية.
هل أحتاج إلى إلغاء المزامنة لكل مسار؟
لا، يعمل FastAPI بشكل متزامنdefالمسارات في تجمع مؤشرات الترابط تلقائيًا. استخدمasync defعند الاتصال بالمكتبات غير المتزامنة (برامج تشغيل قاعدة البيانات غير المتزامنة، httpx) للحصول على فوائد التزامن الحقيقية.
ما الفرق بين Pydantic وSQLModel؟
يتحقق Pydantic من صحة أشكال البيانات للطلبات والاستجابات. يقوم SQLModel بتوسيع نماذج Pydantic بحيث يمكن أيضًا تعيين نفس الفئة إلى جدول قاعدة البيانات، وتجنب تعريفات المخطط المكررة.
كيف أقوم بإضافة المصادقة؟
استخدم FastAPIOAuth2PasswordBearerمع حقن التبعية –get_current_userتقوم التبعية بالتحقق من صحة JWT وتتم إضافتها إلى أي مسار يحتاج إلى الحماية، مع الاحتفاظ بمنطق المصادقة في مكان واحد.
هل يستطيع FastAPI التعامل مع WebSockets؟
نعم وطنيا. تحديد الطريق مع@app.websocket("/ws")وasync defالمعالج الذي ينتظرwebsocket.receive_text()في حلقة.
جاهز للبناء؟
انسخ الكود أعلاه في مشروع جديد، ثم قم بتشغيلuvicorn main:app --reload، وابدأ في توسيع نموذج Todo بحقول مثل تواريخ الاستحقاق أو الأولوية. نمط حقن التبعية الذي استخدمته لجلسة قاعدة البيانات هو نفس النمط الذي ستصل إليه من خلال المصادقة والتخزين المؤقت وتحديد المعدل لاحقًا.
🔗 Share this article
✍️ Leave a Comment