توثيق API وتخصيص OpenAPI — إنشاء توثيق API احترافي
توثيق API مثل كتيب المنتج—بدونه، لن يستخدم العملاء (المطورون) منتجك؛ إذا كان مكتوبًا بشكل سيء، سيصوت العملاء بأقدامهم. إنشاء التوثيق الآلي هو السلاح السري لـ FastAPI، لكن التكوين الافتراضي هو مجرد نقطة البداية؛ التخصيص هو ما يميز المحترفين.
1. ما ستتعلمه
- تكوين Swagger UI و ReDoc:
swagger_ui_parameters، JS/CSS مخصص - تخصيص مخطط OpenAPI:
openapi_route،generate_unique_id_functionمخصص - أفضل ممارسات
description/summary/tags/deprecated - قيم العينات وقوالب الاستجابة:
OpenApiResponse+json_schema_extra - سيناريو Alice: توثيق PriceTracker SaaS API الاحترافي
2. القصة الحقيقية لـ Alice
(1) نقطة الألم: التوثيق الافتراضي ليس احترافيًا بما يكفي
يستخدم توثيق PriceTracker API الخاص بـ Alice واجهة Swagger UI الافتراضية لـ FastAPI، حيث تكون جميع نقاط النهاية مختلطة بدون تجميع، لذا لا يمكن لـ Bob العثور على نقطة النهاية التي يحتاجها. لأسوأ من ذلك، يفتقر التوثيق إلى طلبات نموذجية، لذا لا يعرف Bob ما القيمة التي يجب إدخالها لحقل currency؛ لا يوجد إصدار لهيئات الطلب أو الاستجابة؛ ونقاط النهاية الجديدة والمهملة مختلطة معًا.
(2) حلول تخصيص OpenAPI
يسمح FastAPI بالتخصيص العميق لتوثيق OpenAPI—بما في ذلك تجميع العلامات، وقيم العينات، وعلامات الإهمال، والمخططات المخصصة—تحويل توثيق API من مجرد قابل للقراءة إلى قابل للاستخدام.
(3) العائد
يمكن لـ Bob ببساطة فتح التوثيق لتحديد موقع نقاط النهاية بسرعة حسب العلامة (Products/Prices/Auth). قيم العينات تزيل الحاجة للتخمين عند تقديم الطلبات، ونقاط النهاية المهملة محددة باللون الرمادي لمنع الاستخدام العرضي. نتيجة لذلك، ارتقت جودة التوثيق من مستوى مرجع داخلي إلى مستوى إصدار عام.
3. تكوين Swagger UI و ReDoc
(1) عملية إنشاء OpenAPI
flowchart LR
A[مسارات FastAPI] --> B[نماذج Pydantic]
B --> C[مخطط OpenAPI 3.1]
C --> D[Swagger UI /docs]
C --> E[ReDoc /redoc]
C --> F[JSON خام /openapi.json]
(1) ▶ مثال: تكوين توثيق على مستوى تطبيق FastAPI
from fastapi import FastAPI
app = FastAPI(
title="PriceTracker API",
description="""
## PriceTracker SaaS API
خدمة تتبع أسعار التجارة الإلكترونية لمراقبة أسعار المنتجات بمستوى الملايين.
### (1) المصادقة
جميع نقاط النهاية المحمية تتطلب رمز Bearer يتم الحصول عليه من `/auth/login`.
### (2) حدود المعدل
- مجاني: 100 طلب/دقيقة
- Pro: 1000 طلب/دقيقة
- Enterprise: غير محدود
""",
version="1.0.0",
terms_of_service="https://pricetracker.example.com/terms",
contact={
"name": "PriceTracker Support",
"url": "https://pricetracker.example.com/support",
"email": "support@pricetracker.example.com",
},
license_info={
"name": "MIT License",
"url": "https://opensource.org/licenses/MIT",
},
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
)
الناتج:
# التنفيذ ناجح
(3) ▶ مثال: تخصيص معلمات Swagger UI
app = FastAPI(
swagger_ui_parameters={
"persistAuthorization": True, # الاحتفاظ بالمصادقة بين تحديثات الصفحة
"displayRequestDuration": True, # عرض مدة الطلب
"filter": True, # تمكين فلتر البحث
"syntaxHighlight.theme": "monokai", # سمات تمييز الكود
"defaultModelsExpandDepth": 1, # توسيع النماذج بمستوى عمق واحد
"defaultModelExpandDepth": 1,
}
)
الناتج:
# التنفيذ ناجح
| المعلمة | الافتراضي | الوصف |
|---|---|---|
persistAuthorization |
False | الاحتفاظ بالمصادقة عند تحديث الصفحة |
displayRequestDuration |
False | عرض مدة الطلب |
filter |
False | تمكين فلتر البحث |
defaultModelsExpandDepth |
1 | عمق توسيع النموذج |
syntaxHighlight.theme |
"agate" | سمات تمييز الكود |
4. تجميع العلامات وعلامات الإهمال
(1) العلامات: نقاط النهاية المجمعة
(1) ▶ مثال: تعريف العلامات
from fastapi import FastAPI, APIRouter
tags_metadata = [
{
"name": "auth",
"description": "عمليات المصادقة. تسجيل الدخول، التسجيل، تحديث الرمز.",
},
{
"name": "products",
"description": "إدارة المنتجات. عمليات CRUD للمنتجات المتتبعة.",
},
{
"name": "prices",
"description": "بيانات الأسعار. الاستعلام، الاستيراد، وتتبع تغييرات الأسعار.",
},
{
"name": "admin",
"description": "عمليات المسؤول. تتطلب دور مسؤول.",
},
]
app = FastAPI(
title="PriceTracker API",
openapi_tags=tags_metadata,
)
الناتج:
# التنفيذ ناجح
(2) ▶ مثال: تعيين العلامات لنقاط النهاية
@app.post("/auth/login", tags=["auth"])
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
...
@app.get("/api/v1/products", tags=["products"])
async def list_products():
...
@app.post("/api/v1/prices", tags=["prices"])
async def create_price():
...
@app.get("/api/v1/admin/stats", tags=["admin"])
async def admin_stats():
...
الناتج:
# تم تعريف الدالة بنجاح
(3) ▶ مثال: تحديد نقطة نهاية كمهملة
@app.get(
"/api/v1/products/{product_id}/history",
tags=["prices"],
deprecated=True,
summary="[مهمل] استخدم GET /prices?product_id={id} بدلاً من ذلك",
)
async def get_price_history_deprecated(product_id: int):
"""هذه نقطة نهاية مهملة. استخدم نقطة نهاية الأسعار مع فلتر product_id."""
...
الناتج:
# تم تعريف الدالة بنجاح
5. قيم العينات وقوالب الاستجابة
(1) json_schema_extra و examples
(1) ▶ مثال: قيم عينات لنماذج Pydantic
from pydantic import BaseModel, Field
class ProductCreate(BaseModel):
name: str = Field(
min_length=1, max_length=200,
description="اسم عرض المنتج",
examples=["Wireless Mouse", "USB-C Hub", "Mechanical Keyboard"],
)
category: str = Field(
max_length=100,
description="فئة المنتج",
examples=["electronics", "clothing", "food"],
)
base_price: float = Field(
gt=0,
description="السعر الأساسي بالدولار",
examples=[9.99, 49.99, 199.99],
)
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Wireless Mouse",
"category": "electronics",
"base_price": 29.99,
}
]
}
}
الناتج:
# التنفيذ ناجح
(2) ▶ مثال: مثال استجابة على مستوى نقطة النهاية
from fastapi import FastAPI
from fastapi.responses import JSONResponse
@app.post(
"/api/v1/products",
response_model=ProductResponse,
status_code=201,
summary="إنشاء منتج جديد",
description="إنشاء منتج جديد في قاعدة بيانات PriceTracker.",
responses={
201: {
"description": "تم إنشاء المنتج بنجاح",
"content": {
"application/json": {
"example": {
"id": 1,
"name": "Wireless Mouse",
"category": "electronics",
"base_price": 29.99,
}
}
},
},
401: {"description": "المصادقة مطلوبة"},
403: {"description": "صلاحيات غير كافية"},
422: {"description": "خطأ في التحقق"},
},
)
async def create_product(product: ProductCreate):
...
الناتج:
# تم تعريف الدالة بنجاح
6. مخطط OpenAPI مخصص
(1) generate_unique_id_function
(1) ▶ مثال: إنشاء معرف نقطة نهاية مخصص
from fastapi import FastAPI
def custom_generate_unique_id(route):
# التنسيق: {method}_{tag}_{path}
tags = route.tags or ["default"]
tag = tags[0]
method = route.methods.pop() if route.methods else "GET"
path = route.path.replace("/", "_").strip("_").replace("{", "").replace("}", "")
return f"{method}_{tag}_{path}"
app = FastAPI(
generate_unique_id_function=custom_generate_unique_id,
)
الناتج:
# تم تعريف الدالة بنجاح
(2) مقارنة أفضل ممارسات التوثيق
| البعد | الافتراضي | أفضل ممارسة |
|---|---|---|
| مجموعات نقاط النهاية | بدون | علامات حسب الوظيفة |
| نقاط النهاية المهملة | مختلطة مع النقاط العادية | deprecated=True علامة رمادية |
| مثال الطلب | بدون | examples + json_schema_extra |
| قوالب الاستجابة | 200 فقط | تغطية كاملة لـ 201/401/403/422 |
| الوصف | اسم دالة بسيط | summary + description |
| معلومات المصادقة | بدون | صفحة رئيسية للتوثيق: شرح طرق المصادقة |
| الإصدار | إصدار واحد | إصدار مسار URL /api/v1/ |
❓ أسئلة شائعة
include_in_schema=False:@app.get("/internal", include_in_schema=False). هذا مناسب لفحوصات الصحة الداخلية ونقاط نهاية المراقبة.openapi المخصصة.swagger_ui_parameters لتقديم URL لـ CSS، أو استخدم get_swagger_ui_html لتخصيص HTML بالكامل.APIRouter(prefix="/api/v1") منفصل لكل إصدار وميز بين الإصدارات باستخدام العلامات. بدلاً من ذلك، أنشئ تطبيق FastAPI فرعي منفصل لكل إصدار.📖 ملخص
- FastAPI يُنشئ توثيق OpenAPI 3.1 تلقائيًا؛ Swagger UI يوفر اختبارًا تفاعليًا؛ ReDoc يوفر تجربة قراءة جذابة بصريًا
openapi_tagsتجمع نقاط النهاية حسب الوظيفة؛deprecated=Trueتحدد نقاط النهاية المهملةField(examples=[...])وjson_schema_extraيضيفان قيم عينات إلى النموذجresponses={status: {description, content}}تحدد قوالب استجابة لرموز حالة متعددة لنقاط النهاية- تخصيص
generate_unique_id_functionللتحكم في تنسيق تسمية معرفات عمليات OpenAPI
📝 تمارين
- تمرين أساسي (الصعوبة ⭐): قم بتكوين توثيق على مستوى تطبيق FastAPI لـ PriceTracker—بما في ذلك العنوان والوصف ورقم الإصدار ومعلومات الاتصال—وأضف
persistAuthorization=Trueلضمان احتفاظ Swagger UI بحالة المصادقة. تلميح:FastAPI(title=..., swagger_ui_parameters={...}) - تمرين متقدم (الصعوبة ⭐⭐): عرّف 4 علامات (auth/products/prices/admin)، عين العلامة الصحيحة لكل نقطة نهاية، حدد نقطة النهاية المهملة
deprecated=True، وتحقق من أن نقاط النهاية مجمعة حسب العلامة في Swagger UI. تلميح:openapi_tags=[...]+tags=["products"] - تحدي (الصعوبة ⭐⭐⭐): أضف مثال
json_schema_extraكامل إلى ProductCreate، وأضف قوالب استجابة لرموز الحالة 201 و 401 و 403 و 422 (بما في ذلك محتوى نموذجي) إلى نقطة نهاية POST /products لتنفيذgenerate_unique_id_functionمخصص. تلميح:responses={201: {"content": {...}}}+generate_unique_id_function
---|



