FastAPI: واجهات بايثون حديثة
درس 4 من 6
4FastAPI: واجهات بايثون حديثة
الصورة الكبيرةفي Flask تتحقّق من كل حقل بيدك وتكتب التوثيق منفصلًا. FastAPI يقرأ تلميحات الأنواع في دالتك ويستنتج الاثنين، وهو المفضّل اليوم لخدمات الذكاء الاصطناعي.
ماذا تشاهد في الرسم: قبل أن تصل البيانات لدالتك تكون قد تحقّقت وتحوّلت لأنواع صحيحة، وإلا ردّ FastAPI بـ 422 يشرح كل حقل خاطئ.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
تخيّل نموذج حجز ورقي بخانات محدّدة: «العدد: رقم من 1 إلى 10». الموظّف يرفض أي نموذج خاطئ قبل أن يصل للمدير. في FastAPI أنت تصمّم النموذج (Pydantic)، والإطار هو الموظّف، ودالتك هي المدير الذي لا يرى إلا نماذج صحيحة.
FastAPI مبني على Starlette (ASGI) وPydantic v2. يستنتج من توقيع الدالة مصادر المعاملات (مسار، استعلام، جسم) ويتحقّق ويحوّل الأنواع ويولّد مخطّط OpenAPI تعرضه /docs (Swagger UI). Depends نظام حقن اعتماديات قابل للتركيب (جلسة قاعدة بيانات، مستخدم حالي)، وتستبدله في الاختبارات بـ dependency_overrides. الدوال async def لإدخال/إخراج غير محظور، وdef العادية تُشغَّل في مجمّع خيوط.
قبل أن تبدأ
🐍بايثون والأصناف
تعرف الدوال والأصناف وتلميحات الأنواع البسيطة.
🌐REST
درس REST مع Flask في مسار الواجهات.
الفكرة الجوهرية
1أول مسار والتوثيق المجاني
دالة عادية بمزخرف @app.get. المعامل item_id: int في المسار يتحوّل لرقم ويُرفض النص تلقائيًا. افتح /docs فترى كل مساراتك وتجرّبها من المتصفح.
from fastapi import FastAPI
app = FastAPI(title="Cafe API")
@app.get("/drinks/{item_id}")
def read_drink(item_id: int, size: str = "medium"):
return {"id": item_id, "size": size}
# run with: pip install "fastapi[standard]" then fastapi dev main.py2Pydantic: البيانات بعقد
نموذج Pydantic صنف بأنواع وقيود. يحوّل ويتحقّق ويعطي أخطاء مفصّلة. هذا المثال يعمل بلا خادم لترى التحقّق وحده (يحتاج تثبيت pydantic).
from typing import Literal
from pydantic import BaseModel, Field, ValidationError
class Order(BaseModel):
item: Literal["latte", "mocha", "v60"]
cups: int = Field(ge=1, le=10)
note: str | None = Field(default=None, max_length=80)
print(Order(item="latte", cups="2")) # "2" becomes 2
try:
Order(item="tea", cups=0)
except ValidationError as e:
for err in e.errors():
print(err["loc"][0], "->", err["msg"])3Depends: اعتماديات قابلة للتبديل
ما تحتاجه دوال كثيرة (المستخدم الحالي، جلسة قاعدة البيانات) تكتبه دالة واحدة وتطلبه بـ Depends. وفي الاختبار تستبدلها بنسخة وهمية.
from fastapi import Depends, Header, HTTPException
def current_user(authorization: str = Header()):
if authorization != "Bearer demo-token":
raise HTTPException(status_code=401, detail="log in first")
return {"name": "Sara"}
@app.get("/me")
def me(user: dict = Depends(current_user)):
return userasync def لمسار يستدعي مكتبة متزامنة بطيئة (مثل requests أو قاعدة بيانات متزامنة). تتوقّف حلقة الأحداث لكل الطلبات. إمّا مكتبة async (httpx) أو اجعل الدالة def عادية.4Flask أم FastAPI أم Express؟
Flask بسيط ومرن ومناسب للتعلّم والمواقع الصغيرة. FastAPI حين تريد أنواعًا وتحقّقًا وتوثيقًا تلقائيًا، خصوصًا مع نماذج الذكاء الاصطناعي في بايثون. Express حين فريقك يكتب JavaScript في الواجهة ويريد لغة واحدة.
مثال محلول
واجهة الطلبات بـ FastAPI مع اختبار. لاحظ أنك لا تكتب أي تحقّق يدوي، وأن الخطأ 422 يحدّد الحقل.
from typing import Literal
from fastapi import FastAPI, HTTPException
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field
app = FastAPI()
class NewOrder(BaseModel):
item: Literal["latte", "mocha", "v60"]
cups: int = Field(ge=1, le=10)
class Order(NewOrder):
id: int
ORDERS: list[Order] = []
@app.post("/orders", status_code=201, response_model=Order)
def create(order: NewOrder):
saved = Order(id=len(ORDERS) + 1, **order.model_dump())
ORDERS.append(saved)
return saved
@app.get("/orders/{order_id}", response_model=Order)
def get(order_id: int):
for o in ORDERS:
if o.id == order_id:
return o
raise HTTPException(404, "no such order")
client = TestClient(app)
assert client.post("/orders", json={"item": "latte", "cups": 2}).status_code == 201
bad = client.post("/orders", json={"item": "tea", "cups": 0})
assert bad.status_code == 422
print([e["loc"][-1] for e in bad.json()["detail"]]) # ['item', 'cups']خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| FastAPI أسرع من كل شيء فاستخدمه دائمًا. | سريع لبايثون، لكن قاعدة البيانات والشبكة غالبًا هي عنق الزجاجة لا الإطار. |
| التلميحات في بايثون للتجميل فقط. | في FastAPI وPydantic هي ما يُنفَّذ به التحقّق والتحويل والتوثيق. |
اختبر فهمك
أرسلت cups: 0 والنموذج يقول ge=1. ما الرد؟
FastAPI يرد 422 Unprocessable Entity بتفاصيل كل حقل خاطئ.
أين ترى توثيق واجهتك التفاعلي؟
FastAPI يولّد مخطّط OpenAPI ويعرضه في /docs تلقائيًا.
ما فائدة Depends؟
حقن الاعتماديات يزيل التكرار ويسهّل الاختبار.
بطاقات مراجعة سريعة
تحقق من فهمك
لماذا لا تكتب تحقّقًا يدويًا في FastAPI؟
لأن نموذج Pydantic يصف القيود، والإطار يطبّقها قبل أن تصل البيانات لدالتك.
متى async def ومتى def؟
async def مع مكتبات async (httpx، asyncpg)، وdef العادية مع المكتبات المتزامنة فيشغّلها FastAPI في خيوط.
كيف تختبر مسارًا محميًا دون تسجيل دخول حقيقي؟
app.dependency_overrides[current_user] = lambda: {"name": "test"}.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.