FastAPI: إطارة ويب حديثة عالية الأداء لغة بايثون

أنشئ واجهات برمجة تطبيقات سريعة جدًا مع وثائق تلقائية وسلامة النوع

Page content

FastAPI ظهر كأحد أكثر إطارات الويب لبايثون إثارة للإعجاب في بناء واجهات برمجة التطبيقات، حيث يجمع بين ميزات بايثون الحديثة وأداء متميز وتجربة مطور ممتازة.

سواء كنت تبني خدمات ميكرو، وظائف سيرفرليس، أو تطبيقات ويب معقدة، فإن FastAPI يوفر الأدوات التي تحتاجها لواجهات برمجة التطبيقات الجاهزة للإنتاج.

بايثون وFastAPI قلعة

ما هو FastAPI؟

FastAPI هو إطار ويب حديث وعالي الأداء لبناء واجهات برمجة التطبيقات باستخدام بايثون 3.8+ بناءً على مؤشرات نوع بايثون القياسية. تم إنشاؤه بواسطة Sebastián Ramírez، وتم تصميمه ليكون سهل الاستخدام، سريع الكتابة، وجاهز للإنتاج من البداية.

يقيّم الإطار على كاهل مكتبتين قويتين:

  • Starlette لمسارات الويب والقدرات غير المتزامنة
  • Pydantic لتحقق البيانات باستخدام مؤشرات نوع بايثون

تُوفر هذه المزيج أداءً مقارنًا مع Node.js وGo مع الحفاظ على بساطة ووضوح بايثون. توسعت شعبية FastAPI بسرعة، مع آلاف النجوم على GitHub والتبني من قبل شركات رئيسية حول العالم.

الميزات الرئيسية التي تميز FastAPI

1. وثائق API تلقائية

أحد أكثر ميزات FastAPI إعجابًا هو الوثائق تلقائية وتفاعلية لواجهة API. بناءً على معيار OpenAPI (سابقًا Swagger)، ينشئ FastAPI واجهتين لتوثيق:

  • Swagger UI في /docs - وثائق تفاعلية حيث يمكنك اختبار نقاط نهاية API مباشرة في المتصفح
  • ReDoc في /redoc - وثائق بديلة ذات تصميم نظيف ثلاثي الأقسام

تُنشئ الوثائق تلقائيًا من مؤشرات نوع ونصوص التعليق في الكود - لا حاجة لتكوين إضافي. هذا يعني أن الوثائق دائمًا ما تكون محدثة مع الكود.

2. مؤشرات نوع وتحقق

يستخدم FastAPI مؤشرات نوع بايثون ليس فقط للتوثيق، ولكن أيضًا للتحقق أثناء التشغيل والتسلسل. عندما تحدد معلمة نقطة النهاية كـ int، يقوم FastAPI تلقائيًا:

  • بتأكيد أن الطلب يحتوي على عدد صحيح
  • بتحويل القيمة من سلسلة إلى عدد صحيح
  • بإرجاع رسائل خطأ واضحة إذا فشل التحقق
  • بتوثيق نوع المعلمة في وثائق API
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    username: str
    email: str
    age: int

@app.post("/users/")
async def create_user(user: User):
    return {"message": f"User {user.username} created successfully"}

هذا النهج يكتشف الأخطاء مبكرًا، ويقلل من الكود الزائد، ويجعل واجهة API موثوقة تلقائيًا.

3. الدعم غير المتزامن

تم بناء FastAPI على ASGI (واجهة بوابة الخادم غير المتزامنة) بدلًا من WSGI، مما يمنحه دعمًا داخليًا لـ async/await. هذا أمر حيوي للتطبيقات ذات الأداء العالي التي تجري العديد من مكالمات I/O (الاستعلامات إلى قاعدة البيانات، طلبات API، عمليات الملفات).

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    # العمليات غير المتزامنة لا تمنع طلبات أخرى
    data = await fetch_from_database(item_id)
    return data

يدعم Async FastAPI معالجة آلاف الاتصالات المتزامنة بكفاءة، مما يجعله مثاليًا للتطبيقات السحابية الحديثة وبنية ميكرو الخدمات.

4. الأداء

FastAPI هو أحد أسرع إطارات بايثون المتاحة، مع أداء يشبه Node.js وGo. تظهر المقارنات المستقلة باستمرار أن FastAPI يتفوق بشكل كبير على الإطارات التقليدية مثل Flask وDjango، خاصة في الأحمال المرتبطة بـ I/O.

يأتي هذا الأداء من:

  • التحقق على مستوى C من Pydantic
  • تنفيذ Starlette غير المتزامن الكفء
  • تقليل التحميل الزائد في الإطار نفسه

البدء مع FastAPI

تثبيت FastAPI سهل. عند العمل مع مشاريع بايثون، يسهل وجود مدير حزم بايثون Python package manager إدارة التبعيات. ستحتاج إلى FastAPI ومضيف ASGI مثل Uvicorn:

pip install fastapi uvicorn[standard]

هناك تطبيق FastAPI بسيط:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

قم بتشغيله باستخدام:

uvicorn main:app --reload

قم بزيارة http://localhost:8000/docs لرؤية وثائق API التفاعلية.

بناء واجهات برمجة التطبيقات الجاهزة للإنتاج

نماذج الطلب والرد

تحديد نماذج بيانات واضحة أمر حيوي لواجهات برمجة التطبيقات القابلة للصيانة. يساعد اتباع أنماط تصميم بايثون لعمارة نظيفة في إنشاء تطبيقات منظمة بشكل جيد:

from pydantic import BaseModel, EmailStr, Field
from typing import Optional
from datetime import datetime

class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    password: str = Field(..., min_length=8)

class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    created_at: datetime
    
    class Config:
        orm_mode = True  # يسمح لـ Pydantic بالعمل مع كائنات ORM

@app.post("/users/", response_model=UserResponse)
async def create_user(user: UserCreate):
    # منطق العمل هنا
    new_user = save_user_to_database(user)
    return new_user

يعمل معلمة response_model على ضمان أن FastAPI يعيد فقط الحقول المحددة، تلقائيًا تصفية البيانات الحساسة مثل كلمات المرور.

حقن الاعتماديات

نظام حقن الاعتماديات في FastAPI قوي وجميل. يسمح لك بـ:

  • مشاركة الكود بين نقاط النهاية
  • فرض المصادقة/التوحيد
  • إدارة اتصالات قاعدة البيانات
  • التعامل مع الاعتماديات المعقدة
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_token(token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials"
        )
    return user

@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

معالجة الأخطاء

يوفر FastAPI معالجات استثناء مدمجة وسمح بالرد على الأخطاء المخصصة:

from fastapi import HTTPException

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id not in items_db:
        raise HTTPException(
            status_code=404,
            detail="Item not found",
            headers={"X-Error": "Custom header"}
        )
    return items_db[item_id]

المهام الخلفية

للعمليات التي لا تحتاج إلى الانتهاء قبل إرجاع الرد:

from fastapi import BackgroundTasks

def send_email_notification(email: str, message: str):
    # منطق إرسال البريد الإلكتروني
    pass

@app.post("/send-notification/")
async def send_notification(
    email: str,
    background_tasks: BackgroundTasks
):
    background_tasks.add_task(send_email_notification, email, "Welcome!")
    return {"message": "Notification scheduled"}

اختبار تطبيقات FastAPI

اختبار الاختبارات الوحدوية في بايثون الشامل أمر حيوي لواجهات برمجة التطبيقات الموثوقة. تعمل FastAPI بسلاسة مع pytest وتقدم عميل اختبار:

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello World"}

def test_read_item():
    response = client.get("/items/42?q=test")
    assert response.status_code == 200
    assert response.json() == {"item_id": 42, "q": "test"}

للتحقق من نقاط النهاية غير المتزامنة:

import pytest
from httpx import AsyncClient

@pytest.mark.asyncio
async def test_async_endpoint():
    async with AsyncClient(app=app, base_url="http://test") as ac:
        response = await ac.get("/")
    assert response.status_code == 200

دمج قواعد البيانات

تعمل FastAPI بشكل جيد مع قواعد بيانات متعددة وORMs. إليك مثال مع SQLAlchemy:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from fastapi import Depends

DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True)

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/users/{user_id}")
async def read_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

خيارات النشر

نشر Docker

تطبيقات FastAPI تُحزم بسهولة. إليك ملف Dockerfile جاهز للإنتاج:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

نشر AWS Lambda

يعمل FastAPI بشكل ممتاز مع منصات سيرفرليس. عند بناء AWS Lambda ثنائي النمط مع بايثون وTerraform، يمكنك نشر تطبيقات FastAPI باستخدام Mangum، وهو محول يُحاط FastAPI لـ AWS Lambda:

from mangum import Mangum
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello from Lambda!"}

handler = Mangum(app)

للمشاريع المعقدة أكثر، AWS SAM مع Python PowerTools يوفر أدوات ممتازة لتطبيقات FastAPI.

النشر على الخوادم التقليدية

للنشر على خوادم تقليدية أو Kubernetes:

# مع Gunicorn وعمال Uvicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

الميزات المتقدمة

CORS (مشاركة الموارد عبر المواقع)

تفعيل CORS لتطبيقات الويب الأمامية:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

دعم WebSocket

يدعم FastAPI WebSocket للاتصالات الزمنية الفورية:

from fastapi import WebSocket

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message received: {data}")

دمج GraphQL

يمكن لـ FastAPI العمل مع GraphQL عبر Strawberry أو مكتبات GraphQL أخرى:

import strawberry
from strawberry.fastapi import GraphQLRouter

@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"

schema = strawberry.Schema(query=Query)
graphql_app = GraphQLRouter(schema)

app.include_router(graphql_app, prefix="/graphql")

العمل مع LLMs وAI

FastAPI ممتاز لبناء واجهات برمجة التطبيقات القائمة على الذكاء الاصطناعي. عند تقييد LLMs باستخدام إخراج مهيكل باستخدام Ollama، توفر نماذج Pydantic في FastAPI تعريفات مخطط مثالية للردود المهيكلة:

from pydantic import BaseModel
from typing import List
import httpx

class SentimentResponse(BaseModel):
    sentiment: str
    confidence: float
    keywords: List[str]

@app.post("/analyze-sentiment/", response_model=SentimentResponse)
async def analyze_sentiment(text: str):
    # استدعاء خدمة LLM
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "http://localhost:11434/api/generate",
            json={
                "model": "qwen2.5",
                "prompt": f"Analyze sentiment: {text}",
                "format": SentimentResponse.schema_json()
            }
        )
    return response.json()

أفضل الممارسات والنصائح

1. استخدام مديري عمليات المسارات بشكل متسق

نظم نقاط النهاية مع طرق HTTP واضحة:

@app.get("/items/")      # قائمة العناصر
@app.post("/items/")     # إنشاء عنصر
@app.get("/items/{id}")  # الحصول على عنصر معين
@app.put("/items/{id}")  # تحديث عنصر
@app.delete("/items/{id}") # حذف عنصر

2. إصدار واجهات برمجة التطبيقات

أضف إصدار واجهات برمجة التطبيقات من البداية:

from fastapi import APIRouter

api_v1 = APIRouter(prefix="/api/v1")
api_v2 = APIRouter(prefix="/api/v2")

@api_v1.get("/users/")
async def get_users_v1():
    return {"version": "1.0"}

app.include_router(api_v1)
app.include_router(api_v2)

3. استخدام المتغيرات البيئية

لا تضع السرائر بشكل مباشر. استخدم المتغيرات البيئية:

from pydantic import BaseSettings

class Settings(BaseSettings):
    database_url: str
    secret_key: str
    api_key: str
    
    class Config:
        env_file = ".env"

settings = Settings()

4. تنفيذ تسجيل الأحداث المناسب

استخدم وحدة تسجيل Python:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@app.get("/items/")
async def get_items():
    logger.info("Fetching all items")
    return items

5. مراقبة الأداء

استخدم وسطاء لقياس وقت طلب:

import time
from fastapi import Request

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

FastAPI مقابل الإطارات الأخرى

FastAPI مقابل Flask

Flask أكثر بساطة ويمنحك سيطرة أكبر، ولكن FastAPI يوفر ميزات أكثر من الجاهزة:

  • FastAPI لديه تحقق تلقائي وتوثيق
  • Flask يتطلب ملحقات للدعم غير المتزامن
  • FastAPI أسرع بكثير لعمليات I/O
  • Flask لديه نظام تعلم أكبر وموارد أكثر

FastAPI مقابل Django REST Framework

Django REST Framework (DRF) جزء من النظام الأكبر لـ Django:

  • DRF يحتوي على ORM كامل وواجهة إدارية
  • FastAPI أخف وأسرع
  • DRF أفضل للتطبيقات المعقدة والقوية على قاعدة البيانات
  • FastAPI يتفوق في ميكرو الخدمات وواجهات API المستقلة

FastAPI مقابل Node.js/Express

FastAPI يقدم بساطة بايثون مع أداء مقارن مع Node.js:

  • خصائص أداء غير متزامن متشابهة
  • نظام نوع بايثون أكثر قوة من JavaScript/TypeScript
  • Node.js لديه نظام حزم أكبر
  • توثيق FastAPI تلقائي أفضل

حالات الاستخدام الفعلية

بنية ميكرو الخدمات

الطبيعة الخفيفة لـ FastAPI ووقت التشغيل السريع يجعلها مثالية لميكرو الخدمات. يمكن لكل خدمة أن تُنشر وتُمدد بشكل مستقل.

واجهات برمجة التطبيقات الخاصة بالتعلم الآلي

توصيل نماذج التعلم الآلي هو حالة استخدام شائعة لـ FastAPI. يوفر الإطار دعمًا غير متزامن لمعالجة طلبات التنبؤ المتعددة بكفاءة.

الخلفية لتطبيقات الهاتف / الويب

يكون FastAPI خلفية ممتازة لتطبيقات الويب الحديثة (SPAs) وتطبيقات الهاتف مع معالجة CORS التلقائية ودعم WebSocket.

جمع البيانات من الأجهزة الذكية (IoT)

يمكن لـ FastAPI التعامل مع تحميل البيانات الكبير من أجهزة IoT، مع معالجة وتخزين بيانات المستشعر بكفاءة.

روبوتات المحادثة والذكاء الاصطناعي المحادثة

يؤثر بناء واجهات المحادثة والخلفية لروبوتات المحادثة من FastAPI دعم WebSocket وخصائص غير متزامنة.

الثغرات الشائعة والحلول

1. العمليات الكتلية في الدوال غير المتزامنة

المشكلة: تنفيذ الكود المتزامن الكتلية في الدوال غير المتزامنة:

@app.get("/slow")
async def slow_endpoint():
    time.sleep(10)  # يمنع كل حلقة الأحداث!
    return {"status": "done"}

الحل: استخدام run_in_executor للعمليات الكتلية:

from fastapi import BackgroundTasks
import asyncio

@app.get("/fast")
async def fast_endpoint():
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(None, blocking_function)
    return {"result": result}

2. عدم استخدام نماذج الرد

المشكلة: إرجاع كائنات قاعدة البيانات الخام تكشف عن الهيكل الداخلي.

الحل: تعريف نماذج الرد دائمًا:

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    return db_user  # تلقائيًا مرشح عبر UserResponse

3. معالجة الأخطاء غير الكافية

المشكلة: الأخطاء غير المعالجة تؤدي إلى تعطل التطبيق.

الحل: استخدام معالجات الاستثناء:

@app.exception_handler(ValueError)
async def value_error_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={"message": str(exc)}
    )

موارد النظام البيئي لبايثون

يعمل FastAPI بسلاسة مع النظام البيئي الأوسع لبايثون. لمراجعة شاملة لأساسيات بايثون، تحقق من قائمة اختصارات بايثون التي تغطي القواعد الأساسية لسينتاكس بايثون والأنماط التي ستستخدمها في تطبيقات FastAPI.

الخاتمة

يُمثل FastAPI خطوة كبيرة في تصميم إطارات الويب لبايثون. من خلال تبني ميزات بايثون الحديثة مثل مؤشرات النوع وasync/await، فإنه يوفر أداءً استثنائيًا وتجربة مطور. سواء كنت تبني واجهة برمجة تطبيقات بسيطة أو بنية ميكرو خدمات معقدة، يوفر FastAPI الأدوات والأداء الذي تحتاجه للتطبيقات الجاهزة للإنتاج.

تلقائية الوثائق، أمان النوع، والتصميم المبسط يجعل FastAPI خيارًا ممتازًا للبدء والخبراء. مع استمرار تطور النظام البيئي لبايثون، يضع FastAPI نفسه كإطار لتطوير واجهات برمجة التطبيقات الحديثة.

ابدأ بواجهة بسيطة، استكشف الوثائق، وتبني تدريجيًا ميزات متقدمة مع نمو تطبيقك. مجتمع FastAPI نشط ومفيد، مع وثائق و أمثلة واسعة لمساعدتك.

الروابط المفيدة

الموارد الخارجية والمرجعيات