توسعه API قدرتمند را با FastAPI و Pydantic آزاد کنید. یاد بگیرید که اعتبارسنجی درخواست خودکار، رسیدگی به خطاها و ساخت برنامههای مقیاسپذیر را پیادهسازی کنید.
تسلط بر اعتبارسنجی درخواست FastAPI با مدلهای Pydantic: یک راهنمای جامع
در دنیای توسعه وب مدرن، ساخت APIهای قوی و قابل اعتماد از اهمیت بالایی برخوردار است. یک جزء حیاتی از این استحکام، اعتبارسنجی دادهها است. بدون آن، شما در معرض اصل قدیمی "آشغال وارد شود، آشغال خارج میشود" قرار میگیرید که منجر به اشکالات، آسیبپذیریهای امنیتی و تجربه ضعیف توسعهدهنده برای مصرفکنندگان API شما میشود. اینجاست که ترکیب قدرتمند FastAPI و Pydantic میدرخشد و کاری که قبلاً یک کار طاقتفرسا بود را به یک فرآیند خودکار و زیبا تبدیل میکند.
FastAPI، یک چارچوب وب پایتون با عملکرد بالا، به دلیل سرعت، سادگی و ویژگیهای دوستدار توسعهدهنده، محبوبیت زیادی به دست آورده است. در قلب جادوی آن، یکپارچگی عمیق با Pydantic، یک کتابخانه مدیریت تنظیمات و اعتبارسنجی دادهها، نهفته است. آنها با هم یک راه بیدرز، ایمن از نظر نوع و خود مستند برای ساخت API ارائه میدهند.
این راهنمای جامع شما را به یک غواصی عمیق در استفاده از مدلهای Pydantic برای اعتبارسنجی درخواست در FastAPI میبرد. چه یک مبتدی باشید که تازه با API شروع کردهاید یا یک توسعهدهنده باتجربه که به دنبال سادهسازی گردش کار خود هستید، بینشهای عملی و مثالهای عملی را برای تسلط بر این مهارت ضروری پیدا خواهید کرد.
چرا اعتبارسنجی درخواست برای APIهای مدرن حیاتی است؟
قبل از اینکه به سراغ کد برویم، بیایید مشخص کنیم که چرا اعتبارسنجی ورودی فقط یک ویژگی "خوب است" نیست - این یک ضرورت اساسی است. اعتبارسنجی درخواست مناسب چندین عملکرد حیاتی را انجام میدهد:
- یکپارچگی دادهها: اطمینان حاصل میکند که دادههای وارد شده به سیستم شما با ساختار، انواع و محدودیتهای مورد انتظار مطابقت دارند. این از خراب شدن پایگاه داده شما یا ایجاد رفتار غیرمنتظره برنامه توسط دادههای بدشکل جلوگیری میکند.
- امنیت: با اعتبارسنجی و ضدعفونی کردن تمام دادههای ورودی، یک خط دفاعی اول در برابر تهدیدات امنیتی رایج مانند تزریق NoSQL/SQL، Cross-Site Scripting (XSS) و سایر حملات مبتنی بر محموله ایجاد میکنید.
- تجربه توسعهدهنده (DX): برای مصرفکنندگان API (از جمله تیمهای front-end خودتان)، بازخورد واضح و فوری در مورد درخواستهای نامعتبر بسیار ارزشمند است. به جای خطای 500 سرور عمومی، یک API با اعتبار سنجی شده به خوبی یک خطای 422 دقیق را برمیگرداند و دقیقاً مشخص میکند که کدام فیلدها اشتباه هستند و چرا.
- استحکام و قابلیت اطمینان: اعتبارسنجی دادهها در نقطه ورود برنامه شما از انتشار دادههای نامعتبر به عمق منطق کسب و کار شما جلوگیری میکند. این به طور قابل توجهی احتمال خطاهای زمان اجرا را کاهش میدهد و کدبیس شما را قابل پیشبینیتر و آسانتر برای اشکالزدایی میکند.
زوج قدرتمند: FastAPI و Pydantic
همافزایی بین FastAPI و Pydantic همان چیزی است که این فریمورک را بسیار جذاب میکند. بیایید نقشهای آنها را تجزیه کنیم:
- FastAPI: یک چارچوب وب مدرن که از نکات نوع استاندارد پایتون برای تعریف پارامترهای API و بدنه درخواست استفاده میکند. این بر اساس Starlette برای عملکرد بالا و ASGI برای قابلیتهای ناهمزمان ساخته شده است.
- Pydantic: یک کتابخانه که از این نکات نوع پایتون یکسان برای انجام اعتبارسنجی دادهها، سریالسازی (تبدیل دادهها به و از قالبهایی مانند JSON) و مدیریت تنظیمات استفاده میکند. شما "شکل" دادههای خود را به عنوان یک کلاس تعریف میکنید که از `BaseModel` Pydantic ارثبری میکند.
هنگامی که از یک مدل Pydantic برای اعلام بدنه درخواست در یک عملیات مسیر FastAPI استفاده میکنید، فریمورک به طور خودکار موارد زیر را سازماندهی میکند:
- بدنه درخواست JSON ورودی را میخواند.
- JSON را تجزیه میکند و دادهها را به مدل Pydantic شما منتقل میکند.
- Pydantic دادهها را در برابر انواع و محدودیتهای تعریف شده در مدل شما اعتبارسنجی میکند.
- اگر معتبر باشد، یک نمونه از مدل شما ایجاد میکند و یک شی پایتون کاملاً تایپ شده را در اختیار شما قرار میدهد تا در عملکرد خود کار کنید، که با تکمیل خودکار در ویرایشگر شما تکمیل میشود.
- اگر نامعتبر باشد، FastAPI `ValidationError` Pydantic را شناسایی میکند و به طور خودکار یک پاسخ JSON دقیق با کد وضعیت HTTP 422 Unprocessable Entity برمیگرداند.
- به طور خودکار یک طرح JSON از مدل Pydantic شما ایجاد میکند، که برای تأمین مستندات API تعاملی (Swagger UI و ReDoc) استفاده میشود.
این گردش کار خودکار، کد boilerplate را حذف میکند، خطاها را کاهش میدهد و تعاریف دادهها، قوانین اعتبارسنجی و مستندات شما را کاملاً همگام نگه میدارد.
شروع کار: اعتبارسنجی بدنه درخواست اولیه
بیایید این را با یک مثال ساده در عمل ببینیم. تصور کنید در حال ساخت یک API برای یک پلتفرم تجارت الکترونیک هستیم و به یک نقطه پایانی برای ایجاد یک محصول جدید نیاز داریم.
ابتدا، شکل دادههای محصول خود را با استفاده از یک مدل Pydantic تعریف کنید:
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
# 1. Define the Pydantic model
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
app = FastAPI()
# 2. Use the model in a path operation
@app.post("/items/")
async def create_item(item: Item):
# At this point, 'item' is a validated Pydantic model instance
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
چه اتفاقی در اینجا میافتد؟
در تابع `create_item`، ما پارامتر `item` را به عنوان مدل Pydantic خود، `Item` تایپ کردیم. این سیگنال به FastAPI برای انجام اعتبارسنجی است.
یک درخواست معتبر:
اگر یک کلاینت یک درخواست POST را به `/items/` با یک بدنه JSON معتبر، مانند این ارسال کند:
{
"name": "Super Gadget",
"price": 59.99,
"tax": 5.40
}
FastAPI و Pydantic با موفقیت آن را اعتبارسنجی میکنند. در داخل تابع `create_item` شما، `item` یک نمونه از کلاس `Item` خواهد بود. میتوانید به دادههای آن با استفاده از نماد نقطه (به عنوان مثال، `item.name`، `item.price`) دسترسی داشته باشید و IDE شما تکمیل خودکار کاملی را ارائه میدهد. API یک پاسخ 200 OK با دادههای پردازش شده برمیگرداند.
یک درخواست نامعتبر:
حالا، بیایید ببینیم اگر کلاینت یک درخواست بدشکل را ارسال کند، چه اتفاقی میافتد، به عنوان مثال، قیمت را به عنوان یک رشته به جای یک عدد اعشاری ارسال کند:
{
"name": "Faulty Gadget",
"price": "ninety-nine"
}
شما نیازی به نوشتن یک دستور `if` یا بلوک `try-except` ندارید. FastAPI به طور خودکار خطای اعتبارسنجی را از Pydantic شناسایی میکند و این پاسخ HTTP 422 با جزئیات زیبا را برمیگرداند:
{
"detail": [
{
"loc": [
"body",
"price"
],
"msg": "value is not a valid float",
"type": "type_error.float"
}
]
}
این پیام خطا برای کلاینت بسیار مفید است. این به آنها مکان دقیق خطا (`body` -> `price`)، یک پیام قابل خواندن برای انسان و یک نوع خطای قابل خواندن برای ماشین را میگوید. این قدرت اعتبارسنجی خودکار است.
اعتبارسنجی پیشرفته Pydantic در FastAPI
بررسی نوع اولیه تنها آغاز است. Pydantic مجموعهای غنی از ابزارها را برای قوانین اعتبارسنجی پیچیدهتر ارائه میدهد که همگی به طور یکپارچه با FastAPI ادغام میشوند.
محدودیتها و اعتبارسنجی فیلد
شما میتوانید با استفاده از تابع `Field` از Pydantic (یا `Query`، `Path`، `Body` از FastAPI، که زیر کلاسهای `Field` هستند)، محدودیتهای خاصتری را بر روی فیلدها اعمال کنید.
بیایید یک مدل ثبتنام کاربر با برخی از قوانین اعتبارسنجی رایج ایجاد کنیم:
from pydantic import BaseModel, Field, EmailStr
class UserRegistration(BaseModel):
username: str = Field(
...,
min_length=3,
max_length=50,
regex="^[a-zA-Z0-9_]+$"
)
email: EmailStr # Pydantic has built-in types for common formats
password: str = Field(..., min_length=8)
age: Optional[int] = Field(
None,
gt=0,
le=120,
description="The age must be a positive integer."
)
@app.post("/register/")
async def register_user(user: UserRegistration):
return {"message": f"User {user.username} registered successfully!"}
در این مدل:
- `username` باید بین 3 تا 50 کاراکتر باشد و فقط میتواند شامل کاراکترهای الفبایی و زیرخط باشد.
- `email` به طور خودکار اعتبارسنجی میشود تا مطمئن شود که یک قالب ایمیل معتبر با استفاده از `EmailStr` است.
- `password` باید حداقل 8 کاراکتر طول داشته باشد.
- `age`، در صورت ارائه، باید بزرگتر از 0 (`gt`) و کمتر یا مساوی 120 (`le`) باشد.
- `...` (ellipsis) به عنوان اولین آرگومان برای `Field` نشان میدهد که فیلد مورد نیاز است.
مدلهای تودرتو
APIهای دنیای واقعی اغلب با اشیاء JSON پیچیده و تودرتو سروکار دارند. Pydantic این کار را با ظرافت انجام میدهد و به شما امکان میدهد مدلها را در مدلهای دیگر تعبیه کنید.
from typing import List
class Tag(BaseModel):
id: int
name: str
class Article(BaseModel):
title: str
content: str
tags: List[Tag] = [] # A list of other Pydantic models
author_id: int
@app.post("/articles/")
async def create_article(article: Article):
return article
هنگامی که FastAPI یک درخواست برای این endpoint دریافت میکند، کل ساختار تودرتو را اعتبارسنجی میکند. این اطمینان حاصل میکند که `tags` یک لیست است، و هر آیتم در آن لیست یک شی `Tag` معتبر است (به عنوان مثال، دارای یک `id` عدد صحیح و یک `name` رشته است).
اعتبارسنجهای سفارشی
برای منطق کسبوکاری که با محدودیتهای استاندارد قابل بیان نیست، Pydantic دکوراتور `@validator` را ارائه میدهد. این به شما امکان میدهد عملکردهای اعتبارسنجی خود را بنویسید.
یک مثال کلاسیک تأیید یک فیلد رمز عبور است:
from pydantic import BaseModel, Field, validator
class PasswordChangeRequest(BaseModel):
new_password: str = Field(..., min_length=8)
confirm_password: str
@validator('confirm_password')
def passwords_match(cls, v, values, **kwargs):
# 'v' is the value of 'confirm_password'
# 'values' is a dict of the fields already processed
if 'new_password' in values and v != values['new_password']:
raise ValueError('Passwords do not match')
return v
@app.put("/user/password")
async def change_password(request: PasswordChangeRequest):
# Logic to change the password...
return {"message": "Password updated successfully"}
اگر اعتبارسنجی با شکست مواجه شود (به عنوان مثال، تابع یک `ValueError` را ایجاد میکند)، Pydantic آن را شناسایی میکند و FastAPI آن را به یک پاسخ خطای 422 استاندارد تبدیل میکند، درست مانند قوانین اعتبارسنجی داخلی.
اعتبارسنجی بخشهای مختلف درخواست
در حالی که بدنه درخواست رایجترین مورد استفاده است، FastAPI از اصول اعتبارسنجی مشابه برای سایر قسمتهای یک درخواست HTTP استفاده میکند.
پارامترهای مسیر و پرس و جو
شما میتوانید اعتبارسنجی پیشرفته را به پارامترهای مسیر و پرس و جو با استفاده از `Path` و `Query` از `fastapi` اضافه کنید. اینها درست مانند `Field` Pydantic عمل میکنند.
from fastapi import FastAPI, Path, Query
from typing import List
app = FastAPI()
@app.get("/search/")
async def search(
q: str = Query(..., min_length=3, max_length=50, description="Your search query"),
tags: List[str] = Query([], description="Tags to filter by")
):
return {"query": q, "tags": tags}
@app.get("/files/{file_id}")
async def get_file(
file_id: int = Path(..., gt=0, description="The ID of the file to retrieve")
):
return {"file_id": file_id}
اگر سعی کنید به `/files/0` دسترسی پیدا کنید، FastAPI یک خطای 422 برمیگرداند زیرا `file_id` در اعتبارسنجی `gt=0` (بزرگتر از 0) ناموفق است. به طور مشابه، یک درخواست به `/search/?q=ab` در محدودیت `min_length=3` با شکست مواجه میشود.
مدیریت خطاهای اعتبارسنجی با ظرافت
پاسخ خطای 422 پیشفرض FastAPI عالی است، اما گاهی اوقات برای مطابقت با یک استاندارد خاص یا افزودن ورود به سیستم اضافی، باید آن را سفارشی کنید. FastAPI این کار را با سیستم مدیریت استثنای خود آسان میکند.
شما میتوانید یک هندلر استثنا سفارشی برای `RequestValidationError` ایجاد کنید، که نوع استثنای خاصی است که FastAPI هنگام شکست اعتبارسنجی Pydantic ایجاد میکند.
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
# You can log the error details here
# print(exc.errors())
# print(exc.body)
# Customize the response format
custom_errors = []
for error in exc.errors():
custom_errors.append(
{
"field": ".".join(str(loc) for loc in error["loc"]),
"message": error["msg"],
"type": error["type"]
}
)
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"error": "Validation Failed", "details": custom_errors},
)
# Add an endpoint that can fail validation
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
return item
با این هندلر، یک درخواست نامعتبر اکنون یک پاسخ 400 Bad Request را با ساختار JSON سفارشی شما دریافت میکند و به شما کنترل کاملی بر قالب خطای ارائه شده توسط API خود میدهد.
بهترین شیوهها برای مدلهای Pydantic در FastAPI
برای ساخت برنامههای مقیاسپذیر و قابل نگهداری، این بهترین شیوهها را در نظر بگیرید:
- مدلها را DRY (خودت را تکرار نکن) نگه دارید: از وراثت مدل برای جلوگیری از تکرار استفاده کنید. یک مدل پایه با فیلدهای مشترک ایجاد کنید، سپس آن را برای موارد استفاده خاص مانند ایجاد (که ممکن است فیلدهای `id` و `created_at` را حذف کند) و خواندن (که شامل همه فیلدها میشود) گسترش دهید.
- مدلهای ورودی و خروجی را جدا کنید: دادههایی که به عنوان ورودی (`POST`/`PUT`) میپذیرید اغلب با دادههایی که برمیگردانید (`GET`) متفاوت است. به عنوان مثال، هرگز نباید هش رمز عبور یک کاربر را در پاسخ API برگردانید. از پارامتر `response_model` در دکوراتور عملیات مسیر خود برای تعریف یک مدل Pydantic خاص برای خروجی استفاده کنید، و اطمینان حاصل کنید که دادههای حساس هرگز به طور تصادفی در معرض دید قرار نمیگیرند.
- از انواع دادههای خاص استفاده کنید: از مجموعه غنی انواع خاص Pydantic مانند `EmailStr`، `HttpUrl`، `UUID`، `datetime` و `date` استفاده کنید. آنها اعتبارسنجی داخلی را برای قالبهای رایج ارائه میدهند و مدلهای شما را قویتر و گویاتر میکنند.
- مدلها را با کلاس `Config` پیکربندی کنید: مدلهای Pydantic را میتوان از طریق یک کلاس داخلی `Config` سفارشی کرد. یک تنظیم کلیدی برای ادغام پایگاه داده `from_attributes=True` است (که قبلاً `orm_mode=True` در Pydantic v1 بود)، که به مدل اجازه میدهد با دسترسی به ویژگیها به جای کلیدهای دیکشنری، از اشیاء ORM (مانند اشیاء SQLAlchemy یا Tortoise ORM) پر شود.
نتیجه
ادغام یکپارچه Pydantic بدون شک یکی از ویژگیهای برجسته FastAPI است. این کار توسعه API را با خودکارسازی وظایف حیاتی اما اغلب خسته کننده اعتبارسنجی دادهها، سریالسازی و مستندات ارتقا میدهد. با تعریف اشکال دادههای خود یک بار با مدلهای Pydantic، مجموعهای از مزایا را به دست میآورید: امنیت قوی، بهبود یکپارچگی دادهها، تجربه توسعهدهنده برتر برای مصرفکنندگان API شما، و کدبیس قابل نگهداریتر برای خودتان.
با انتقال منطق اعتبارسنجی از کد کسبوکار خود به مدلهای داده اعلامی، APIهایی ایجاد میکنید که نه تنها سریع اجرا میشوند، بلکه ساختن آنها نیز سریع، درک آنها آسان و استفاده از آنها ایمن است. بنابراین، دفعه بعد که یک پروژه API پایتون جدید را شروع میکنید، قدرت FastAPI و Pydantic را در آغوش بگیرید تا خدمات واقعاً درجه حرفهای بسازید.