mirror of https://github.com/tiangolo/fastapi.git
🔥 Remove inactive/scarce translations to Persian
This commit is contained in:
parent
01bb87275b
commit
b4efdf0d9c
|
|
@ -1,66 +0,0 @@
|
||||||
# زیر برنامه ها - اتصال
|
|
||||||
|
|
||||||
اگر نیاز دارید که دو برنامه مستقل FastAPI، با OpenAPI مستقل و رابطهای کاربری اسناد خود داشته باشید، میتوانید یک برنامه
|
|
||||||
اصلی داشته باشید و یک (یا چند) زیر برنامه را به آن متصل کنید.
|
|
||||||
|
|
||||||
## اتصال (mount) به یک برنامه **FastAPI**
|
|
||||||
|
|
||||||
کلمه "Mounting" به معنای افزودن یک برنامه کاملاً مستقل در یک مسیر خاص است، که پس از آن مدیریت همه چیز در آن مسیر، با path operations (عملیات های مسیر) اعلام شده در آن زیر برنامه می باشد.
|
|
||||||
|
|
||||||
### برنامه سطح بالا
|
|
||||||
|
|
||||||
ابتدا برنامه اصلی سطح بالا، **FastAPI** و path operations آن را ایجاد کنید:
|
|
||||||
|
|
||||||
|
|
||||||
{* ../../docs_src/sub_applications/tutorial001.py hl[3,6:8] *}
|
|
||||||
|
|
||||||
### زیر برنامه
|
|
||||||
|
|
||||||
سپس، زیر برنامه خود و path operations آن را ایجاد کنید.
|
|
||||||
|
|
||||||
این زیر برنامه فقط یکی دیگر از برنامه های استاندارد FastAPI است، اما این برنامه ای است که متصل می شود:
|
|
||||||
|
|
||||||
{* ../../docs_src/sub_applications/tutorial001.py hl[11,14:16] *}
|
|
||||||
|
|
||||||
### اتصال زیر برنامه
|
|
||||||
|
|
||||||
در برنامه سطح بالا `app` اتصال زیر برنامه `subapi` در این نمونه `/subapi` در مسیر قرار میدهد و میشود:
|
|
||||||
|
|
||||||
{* ../../docs_src/sub_applications/tutorial001.py hl[11,19] *}
|
|
||||||
|
|
||||||
### اسناد API خودکار را بررسی کنید
|
|
||||||
|
|
||||||
برنامه را با استفاده از ‘uvicorn‘ اجرا کنید، اگر فایل شما ‘main.py‘ نام دارد، دستور زیر را وارد کنید:
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ uvicorn main:app --reload
|
|
||||||
|
|
||||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
صفحه مستندات را در آدرس <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> باز کنید.
|
|
||||||
|
|
||||||
اسناد API خودکار برنامه اصلی را مشاهده خواهید کرد که فقط شامل path operations خود می شود:
|
|
||||||
|
|
||||||
<img src="/img/tutorial/sub-applications/image01.png">
|
|
||||||
|
|
||||||
و سپس اسناد زیر برنامه را در آدرس <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>. باز کنید.
|
|
||||||
|
|
||||||
اسناد API خودکار برای زیر برنامه را خواهید دید، که فقط شامل path operations خود می شود، همه در زیر مسیر `/subapi` قرار دارند:
|
|
||||||
|
|
||||||
<img src="/img/tutorial/sub-applications/image02.png">
|
|
||||||
|
|
||||||
اگر سعی کنید با هر یک از این دو رابط کاربری تعامل داشته باشید، آنها به درستی کار می کنند، زیرا مرورگر می تواند با هر یک از برنامه ها یا زیر برنامه های خاص صحبت کند.
|
|
||||||
|
|
||||||
### جرئیات فنی : `root_path`
|
|
||||||
|
|
||||||
هنگامی که یک زیر برنامه را همانطور که در بالا توضیح داده شد متصل می کنید, FastAPI با استفاده از مکانیزمی از مشخصات ASGI به نام `root_path` ارتباط مسیر mount را برای زیر برنامه انجام می دهد.
|
|
||||||
|
|
||||||
به این ترتیب، زیر برنامه می داند که از آن پیشوند مسیر برای رابط کاربری اسناد (docs UI) استفاده کند.
|
|
||||||
|
|
||||||
و زیر برنامه ها نیز می تواند زیر برنامه های متصل شده خود را داشته باشد و همه چیز به درستی کار کند، زیرا FastAPI تمام این مسیرهای `root_path` را به طور خودکار مدیریت می کند.
|
|
||||||
|
|
||||||
در بخش [پشت پراکسی](behind-a-proxy.md){.internal-link target=_blank}. درباره `root_path` و نحوه استفاده درست از آن بیشتر خواهید آموخت.
|
|
||||||
|
|
@ -1,444 +0,0 @@
|
||||||
# همزمانی و async / await
|
|
||||||
|
|
||||||
جزئیات در مورد سینتکس `async def` برای *توابع عملیات مسیر* و یه کم پیشزمینه در مورد کد ناهمزمان، همزمانی و موازیسازی.
|
|
||||||
|
|
||||||
## عجله داری؟
|
|
||||||
|
|
||||||
<abbr title="خیلی طولانی بود؛ نخوندم"><strong>TL;DR:</strong></abbr>
|
|
||||||
|
|
||||||
اگه از کتابخونههای سومشخصی استفاده میکنی که بهت میگن با `await` صداشون کنی، مثل:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
results = await some_library()
|
|
||||||
```
|
|
||||||
|
|
||||||
اون وقت، *توابع عملیات مسیرت* رو با `async def` تعریف کن، اینجوری:
|
|
||||||
|
|
||||||
```Python hl_lines="2"
|
|
||||||
@app.get('/')
|
|
||||||
async def read_results():
|
|
||||||
results = await some_library()
|
|
||||||
return results
|
|
||||||
```
|
|
||||||
|
|
||||||
/// note
|
|
||||||
|
|
||||||
فقط توی توابعی که با `async def` ساخته شدن میتونی از `await` استفاده کنی.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
اگه از یه کتابخونه سومشخص استفاده میکنی که با یه چیزی (مثل دیتابیس، API، سیستم فایل و غیره) ارتباط داره و از `await` پشتیبانی نمیکنه (که الان برای بیشتر کتابخونههای دیتابیس اینجوریه)، اون وقت *توابع عملیات مسیرت* رو عادی، فقط با `def` تعریف کن، اینجوری:
|
|
||||||
|
|
||||||
```Python hl_lines="2"
|
|
||||||
@app.get('/')
|
|
||||||
def results():
|
|
||||||
results = some_library()
|
|
||||||
return results
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
اگه برنامهات (به هر دلیلی) لازم نیست با چیز دیگهای ارتباط برقرار کنه و منتظر جوابش بمونه، از `async def` استفاده کن.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
اگه نمیدونی چیکار کنی، از `def` معمولی استفاده کن.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**توجه**: میتونی توی *توابع عملیات مسیرت* هر چقدر که لازم داری `def` و `async def` رو قاطی کنی و هر کدوم رو با بهترین گزینه برات تعریف کنی. FastAPI خودش کار درست رو باهاشون انجام میده.
|
|
||||||
|
|
||||||
به هر حال، توی هر کدوم از موقعیتهای بالا، FastAPI هنوز ناهمزمان کار میکنه و خیلی خیلی سریع هست.
|
|
||||||
|
|
||||||
ولی با دنبال کردن مراحل بالا، میتونه یه سری بهینهسازی عملکرد هم بکنه.
|
|
||||||
|
|
||||||
## جزئیات فنی
|
|
||||||
|
|
||||||
نسخههای مدرن پایتون از **"کد ناهمزمان"** با چیزی که بهش **"کروتین"** میگن پشتیبانی میکنن، با سینتکس **`async` و `await`**.
|
|
||||||
|
|
||||||
بیاید این جمله رو تکهتکه توی بخشهای زیر ببینیم:
|
|
||||||
|
|
||||||
* **کد ناهمزمان**
|
|
||||||
* **`async` و `await`**
|
|
||||||
* **کروتینها**
|
|
||||||
|
|
||||||
## کد ناهمزمان
|
|
||||||
|
|
||||||
کد ناهمزمان یعنی زبون 💬 یه راهی داره که به کامپیوتر / برنامه 🤖 بگه توی یه جای کد، باید منتظر بمونه تا *یه چیز دیگه* یه جای دیگه تموم بشه. فرض کن اون *یه چیز دیگه* اسمش "فایل-آروم" 📝 باشه.
|
|
||||||
|
|
||||||
پس، توی اون مدت، کامپیوتر میتونه بره یه کار دیگه بکنه، تا وقتی "فایل-آروم" 📝 تموم بشه.
|
|
||||||
|
|
||||||
بعدش کامپیوتر / برنامه 🤖 هر وقت فرصتی داشته باشه برمیگرده، چون دوباره منتظره، یا هر وقت همه کاری که اون لحظه داشته تموم کرده. و میبینه آیا کارایی که منتظرشون بوده تموم شدن یا نه، و هر کاری که باید بکنه رو انجام میده.
|
|
||||||
|
|
||||||
بعد، اون 🤖 اولین کاری که تموم شده (مثلاً "فایل-آروم" 📝 ما) رو برمیداره و هر کاری که باید باهاش بکنه رو ادامه میده.
|
|
||||||
|
|
||||||
این "منتظر یه چیز دیگه بودن" معمولاً به عملیات <abbr title="ورودی و خروجی">I/O</abbr> اشاره داره که نسبتاً "آروم" هستن (نسبت به سرعت پردازنده و حافظه RAM)، مثل منتظر موندن برای:
|
|
||||||
|
|
||||||
* دادههایی که از کلاینت از طریق شبکه فرستاده میشن
|
|
||||||
* دادههایی که برنامهات فرستاده تا از طریق شبکه به کلاینت برسه
|
|
||||||
* محتوای یه فایل توی دیسک که سیستم بخوندش و به برنامهات بده
|
|
||||||
* محتوایی که برنامهات به سیستم داده تا توی دیسک بنویسه
|
|
||||||
* یه عملیات API از راه دور
|
|
||||||
* یه عملیات دیتابیس که تموم بشه
|
|
||||||
* یه کوئری دیتابیس که نتایجش برگرده
|
|
||||||
* و غیره.
|
|
||||||
|
|
||||||
چون زمان اجرا بیشتر صرف انتظار برای عملیات <abbr title="ورودی و خروجی">I/O</abbr> میشه، بهشون میگن عملیات "I/O bound".
|
|
||||||
|
|
||||||
بهش "ناهمزمان" میگن چون کامپیوتر / برنامه لازم نیست با کار آروم "همزمان" باشه، منتظر لحظه دقیق تموم شدن کار بمونه، در حالی که هیچ کاری نمیکنه، تا نتیجه رو بگیره و کارش رو ادامه بده.
|
|
||||||
|
|
||||||
به جاش، چون یه سیستم "ناهمزمان" هست، وقتی کار تموم شد، میتونه یه کم توی صف منتظر بمونه (چند میکروثانیه) تا کامپیوتر / برنامه هر کاری که رفته بکنه رو تموم کنه، و بعد برگرده نتیجه رو بگیره و باهاش کار کنه.
|
|
||||||
|
|
||||||
برای "همزمان" (برخلاف "ناهمزمان") معمولاً از اصطلاح "ترتیبی" هم استفاده میکنن، چون کامپیوتر / برنامه همه مراحل رو به ترتیب دنبال میکنه قبل از اینکه بره سراغ یه کار دیگه، حتی اگه اون مراحل شامل انتظار باشن.
|
|
||||||
|
|
||||||
### همزمانی و برگرها
|
|
||||||
|
|
||||||
این ایده **ناهمزمان** که بالا توضیح دادم گاهی بهش **"همزمانی"** هم میگن. با **"موازیسازی"** فرق داره.
|
|
||||||
|
|
||||||
**همزمانی** و **موازیسازی** هر دو به "اتفاق افتادن چیزای مختلف کموبیش همزمان" ربط دارن.
|
|
||||||
|
|
||||||
ولی جزئیات بین *همزمانی* و *موازیسازی* خیلی متفاوته.
|
|
||||||
|
|
||||||
برای دیدن فرقش، این داستان در مورد برگرها رو تصور کن:
|
|
||||||
|
|
||||||
### برگرهای همزمان
|
|
||||||
|
|
||||||
با عشقت میری فستفود بگیرین، توی صف وایمیستی در حالی که صندوقدار سفارش آدمای جلوی تو رو میگیره. 😍
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
|
|
||||||
|
|
||||||
بعد نوبت تو میشه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت میدی. 🍔🍔
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
|
|
||||||
|
|
||||||
صندوقدار یه چیزی به آشپز توی آشپزخونه میگه تا بدونن باید برگرهای تو رو آماده کنن (گرچه الان دارن برگرهای مشتریای قبلی رو درست میکنن).
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
|
|
||||||
|
|
||||||
پول رو میدی. 💸
|
|
||||||
|
|
||||||
صندوقدار شماره نوبتت رو بهت میده.
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
|
|
||||||
|
|
||||||
وقتی منتظری، با عشقت میری یه میز انتخاب میکنی، میشینی و کلی با عشقت حرف میزنی (چون برگرهات خیلی شیکن و آماده کردنشون یه کم طول میکشه).
|
|
||||||
|
|
||||||
وقتی پشت میز با عشقت نشستی، در حالی که منتظر برگرهایی، میتونی اون زمان رو صرف تحسین این کنی که عشقت چقدر باحال، ناز و باهوشه ✨😍✨.
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
|
|
||||||
|
|
||||||
وقتی منتظری و با عشقت حرف میزنی، هر از گاهی شمارهای که رو پیشخون نشون داده میشه رو چک میکنی که ببینی نوبتت شده یا نه.
|
|
||||||
|
|
||||||
بعد یه جایی بالاخره نوبتت میشه. میری پیشخون، برگرهات رو میگیری و برمیگردی سر میز.
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
|
|
||||||
|
|
||||||
تو و عشقت برگرها رو میخورین و یه وقت خوب باهم دارین. ✨
|
|
||||||
|
|
||||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
|
|
||||||
|
|
||||||
/// info
|
|
||||||
|
|
||||||
تصاویر قشنگ از <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">کترینا تامپسون</a>. 🎨
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
تصور کن تو توی این داستان کامپیوتر / برنامه 🤖 هستی.
|
|
||||||
|
|
||||||
وقتی توی صف هستی، فقط بیکاری 😴، منتظر نوبتت هستی، کار خیلی "مفیدی" نمیکنی. ولی صف سریع پیش میره چون صندوقدار فقط سفارش میگیره (آمادشون نمیکنه)، پس این خوبه.
|
|
||||||
|
|
||||||
بعد، وقتی نوبتت میشه، کار "مفید" واقعی میکنی، منو رو پردازش میکنی، تصمیم میگیری چی میخوای، انتخاب عشقت رو میگیری، پول میدی، چک میکنی اسکناس یا کارت درست رو دادی، چک میکنی درست حساب شده، چک میکنی سفارش آیتمای درست رو داره و غیره.
|
|
||||||
|
|
||||||
ولی بعد، گرچه هنوز برگرهات رو نداری، کارت با صندوقدار "موقتاً متوقف" ⏸ میشه، چون باید منتظر بمونی 🕙 تا برگرهات آماده بشن.
|
|
||||||
|
|
||||||
ولی وقتی از پیشخون دور میشی و با شماره نوبتت سر میز میشینی، میتونی توجهت رو 🔀 به عشقت بدی و "کار" ⏯ 🤓 رو اون بکنی. بعدش دوباره داری یه چیز خیلی "مفید" انجام میدی، مثل لاس زدن با عشقت 😍.
|
|
||||||
|
|
||||||
بعد صندوقدار 💁 با گذاشتن شمارهات رو نمایشگر پیشخون میگه "من با درست کردن برگرها تموم کردم"، ولی تو مثل دیوونهها وقتی شمارهات رو نمایشگر میاد فوری نمیپری. میدونی کسی برگرهات رو نمیدزده چون شماره نوبتت رو داری، و اونا هم مال خودشون رو دارن.
|
|
||||||
|
|
||||||
پس منتظر میمونی تا عشقت داستانش رو تموم کنه (کار فعلی ⏯ / وظیفهای که داره پردازش میشه 🤓)، آروم لبخند میزنی و میگی که میری برگرها رو بیاری ⏸.
|
|
||||||
|
|
||||||
بعد میری پیشخون 🔀، به کار اولیه که حالا تموم شده ⏯، برگرها رو میگیری، تشکر میکنی و میبرشون سر میز. این مرحله / وظیفه تعامل با پیشخون رو تموم میکنه ⏹. این به نوبه خودش یه وظیفه جدید، "خوردن برگرها" 🔀 ⏯، میسازه، ولی اون قبلی که "گرفتن برگرها" بود تموم شده ⏹.
|
|
||||||
|
|
||||||
### برگرهای موازی
|
|
||||||
|
|
||||||
حالا فرض کن اینا "برگرهای همزمان" نیستن، بلکه "برگرهای موازی" هستن.
|
|
||||||
|
|
||||||
با عشقت میری فستفود موازی بگیری.
|
|
||||||
|
|
||||||
توی صف وایمیستی در حالی که چند تا (مثلاً 8 تا) صندوقدار که همزمان آشپز هم هستن سفارش آدمای جلوی تو رو میگیرن.
|
|
||||||
|
|
||||||
همه قبل تو منتظرن برگرهاشون آماده بشه قبل از اینکه پیشخون رو ترک کنن، چون هر کدوم از 8 تا صندوقدار میره و برگر رو همون موقع درست میکنه قبل از اینکه سفارش بعدی رو بگیره.
|
|
||||||
|
|
||||||
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
|
|
||||||
|
|
||||||
بالاخره نوبت تو میشه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت میدی.
|
|
||||||
|
|
||||||
پول رو میدی 💸.
|
|
||||||
|
|
||||||
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
|
|
||||||
|
|
||||||
صندوقدار میره آشپزخونه.
|
|
||||||
|
|
||||||
منتظر میمونی، جلوی پیشخون وایستادی 🕙، که کسی قبل از تو برگرهات رو نگیره، چون شماره نوبت نیست.
|
|
||||||
|
|
||||||
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
|
|
||||||
|
|
||||||
چون تو و عشقت مشغول این هستین که نذارین کسی جلوتون بیاد و هر وقت برگرها رسیدن اونا رو بگیره، نمیتونی به عشقت توجه کنی. 😞
|
|
||||||
|
|
||||||
این کار "همزمان" هست، تو با صندوقدار/آشپز 👨🍳 "همزمان" هستی. باید منتظر بمونی 🕙 و درست همون لحظه که صندوقدار/آشپز 👨🍳 برگرها رو تموم میکنه و بهت میده اونجا باشی، وگرنه ممکنه یکی دیگه اونا رو بگیره.
|
|
||||||
|
|
||||||
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
|
|
||||||
|
|
||||||
بعد صندوقدار/آشپزت 👨🍳 بالاخره بعد از یه مدت طولانی انتظار 🕙 جلوی پیشخون با برگرهات برمیگرده.
|
|
||||||
|
|
||||||
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
|
|
||||||
|
|
||||||
برگرهات رو میگیری و با عشقت میری سر میز.
|
|
||||||
|
|
||||||
فقط میخورینشون، و تمومه. ⏹
|
|
||||||
|
|
||||||
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
|
|
||||||
|
|
||||||
حرف زدن یا لاس زدن زیاد نبود چون بیشتر وقت صرف انتظار 🕙 جلوی پیشخون شد. 😞
|
|
||||||
|
|
||||||
/// info
|
|
||||||
|
|
||||||
تصاویر قشنگ از <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">کترینا تامپسون</a>. 🎨
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
توی این سناریوی برگرهای موازی، تو یه کامپیوتر / برنامه 🤖 با دو تا پردازنده (تو و عشقت) هستی، هر دو منتظر 🕙 و توجهشون ⏯ رو برای مدت طولانی "انتظار جلوی پیشخون" 🕙 گذاشتن.
|
|
||||||
|
|
||||||
فستفود 8 تا پردازنده (صندوقدار/آشپز) داره. در حالی که فستفود برگرهای همزمان شاید فقط 2 تا داشته (یه صندوقدار و یه آشپز).
|
|
||||||
|
|
||||||
ولی با این حال، تجربه نهایی بهترین نیست. 😞
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
این معادل موازی داستان برگرها بود. 🍔
|
|
||||||
|
|
||||||
برای یه مثال "واقعیتر" از زندگی، یه بانک رو تصور کن.
|
|
||||||
|
|
||||||
تا همین چند وقت پیش، بیشتر بانکها چند تا صندوقدار 👨💼👨💼👨💼👨💼 داشتن و یه صف بزرگ 🕙🕙🕙🕙🕙🕙🕙🕙.
|
|
||||||
|
|
||||||
همه صندوقدارها کار رو با یه مشتری بعد از اون یکی 👨💼⏯ انجام میدادن.
|
|
||||||
|
|
||||||
و باید توی صف 🕙 مدت زیادی منتظر بمونی وگرنه نوبتت رو از دست میدی.
|
|
||||||
|
|
||||||
احتمالاً نمیخوای عشقت 😍 رو با خودت ببری بانک 🏦 برای کارای روزمره.
|
|
||||||
|
|
||||||
### نتیجهگیری برگرها
|
|
||||||
|
|
||||||
توی این سناریوی "برگرهای فستفود با عشقت"، چون کلی انتظار 🕙 هست، خیلی منطقیتره که یه سیستم همزمان ⏸🔀⏯ داشته باشی.
|
|
||||||
|
|
||||||
این برای بیشتر برنامههای وب هم صدق میکنه.
|
|
||||||
|
|
||||||
خیلی خیلی کاربر، ولی سرورت منتظر 🕙 اتصال نهچندان خوبشون هست تا درخواستهاشون رو بفرستن.
|
|
||||||
|
|
||||||
و بعد دوباره منتظر 🕙 که جوابها برگردن.
|
|
||||||
|
|
||||||
این "انتظار" 🕙 توی میکروثانیهها اندازهگیری میشه، ولی با این حال، جمعش که بکنی آخرش کلی انتظار میشه.
|
|
||||||
|
|
||||||
برای همین استفاده از کد ناهمزمان ⏸🔀⏯ برای APIهای وب خیلی منطقیه.
|
|
||||||
|
|
||||||
این نوع ناهمزمانی چیزیه که NodeJS رو محبوب کرد (گرچه NodeJS موازی نیست) و نقطه قوت Go بهعنوان یه زبون برنامهنویسیه.
|
|
||||||
|
|
||||||
و همون سطح عملکردی هست که با **FastAPI** میگیری.
|
|
||||||
|
|
||||||
و چون میتونی همزمانی و موازیسازی رو همزمان داشته باشی، عملکرد بالاتری از بیشتر فریمورکهای تستشده NodeJS میگیری و همتراز با Go، که یه زبون کامپایلشده نزدیک به C هست <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(همه اینا به لطف Starlette)</a>.
|
|
||||||
|
|
||||||
### آیا همزمانی از موازیسازی بهتره؟
|
|
||||||
|
|
||||||
نه! این نتیجه داستان نیست.
|
|
||||||
|
|
||||||
همزمانی با موازیسازی فرق داره. و توی **سناریوهای خاص** که کلی انتظار دارن بهتره. به همین خاطر، معمولاً برای توسعه برنامههای وب خیلی از موازیسازی بهتره. ولی نه برای همهچیز.
|
|
||||||
|
|
||||||
برای اینکه یه تعادل بذاریم، این داستان کوتاه رو تصور کن:
|
|
||||||
|
|
||||||
> باید یه خونه بزرگ و کثیف رو تمیز کنی.
|
|
||||||
|
|
||||||
*آره، کل داستان همینه*.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
هیچ انتظاری 🕙 اونجا نیست، فقط کلی کار برای انجام دادن توی جاهای مختلف خونه.
|
|
||||||
|
|
||||||
میتونی مثل مثال برگرها نوبت بذاری، اول پذیرایی، بعد آشپزخونه، ولی چون منتظر چیزی نیستی 🕙، فقط داری تمیز میکنی و تمیز میکنی، نوبتها هیچ تأثیری نداره.
|
|
||||||
|
|
||||||
با نوبت یا بدون نوبت (همزمانی) همون قدر طول میکشه تا تمومش کنی و همون مقدار کار رو کردی.
|
|
||||||
|
|
||||||
ولی توی این موقعیت، اگه بتونی اون 8 تا صندوقدار/آشپز/حالا-تمیزکار رو بیاری، و هر کدومشون (بهعلاوه خودت) یه قسمت از خونه رو تمیز کنن، میتونی همه کار رو **موازی** انجام بدی، با کمک اضافی، و خیلی زودتر تمومش کنی.
|
|
||||||
|
|
||||||
توی این سناریو، هر کدوم از تمیزکارها (از جمله خودت) یه پردازندهست که کار خودش رو میکنه.
|
|
||||||
|
|
||||||
و چون بیشتر زمان اجرا صرف کار واقعی میشه (به جای انتظار)، و کار توی کامپیوتر با <abbr title="واحد پردازش مرکزی">CPU</abbr> انجام میشه، به این مشکلات میگن "CPU bound".
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
مثالهای رایج عملیات CPU bound چیزایی هستن که نیاز به پردازش ریاضی پیچیده دارن.
|
|
||||||
|
|
||||||
مثلاً:
|
|
||||||
|
|
||||||
* پردازش **صدا** یا **تصویر**.
|
|
||||||
* **بینایی کامپیوتری**: یه تصویر از میلیونها پیکسل تشکیل شده، هر پیکسل 3 تا مقدار / رنگ داره، پردازشش معمولاً نیاز داره چیزی رو رو اون پیکسلها همزمان حساب کنی.
|
|
||||||
* **یادگیری ماشین**: معمولاً کلی ضرب "ماتریس" و "بردار" لازم داره. یه جدول بزرگ پر از عدد رو تصور کن که همهشون رو همزمان ضرب میکنی.
|
|
||||||
* **یادگیری عمیق**: این یه زیرشاخه از یادگیری ماشینه، پس همون قضیه صدق میکنه. فقط این که یه جدول عدد برای ضرب کردن نیست، بلکه یه مجموعه بزرگ از اونا هست، و توی خیلی موارد از یه پردازنده خاص برای ساخت و / یا استفاده از این مدلها استفاده میکنی.
|
|
||||||
|
|
||||||
### همزمانی + موازیسازی: وب + یادگیری ماشین
|
|
||||||
|
|
||||||
با **FastAPI** میتونی از همزمانی که برای توسعه وب خیلی رایجه (همون جذابیت اصلی NodeJS) استفاده کنی.
|
|
||||||
|
|
||||||
ولی میتونی از فواید موازیسازی و چندپردازشی (اجرای چند پروسه بهصورت موازی) برای کارای **CPU bound** مثل سیستمهای یادگیری ماشین هم بهره ببری.
|
|
||||||
|
|
||||||
این، بهعلاوه این واقعیت ساده که پایتون زبون اصلی برای **علم داده**، یادگیری ماشین و بهخصوص یادگیری عمیقه، باعث میشه FastAPI یه انتخاب خیلی خوب برای APIها و برنامههای وب علم داده / یادگیری ماشین باشه (بین خیلی چیزای دیگه).
|
|
||||||
|
|
||||||
برای دیدن اینکه چطور توی محیط واقعی به این موازیسازی برسی، بخش [استقرار](deployment/index.md){.internal-link target=_blank} رو ببین.
|
|
||||||
|
|
||||||
## `async` و `await`
|
|
||||||
|
|
||||||
نسخههای مدرن پایتون یه راه خیلی ساده و قابلفهم برای تعریف کد ناهمزمان دارن. این باعث میشه مثل کد "ترتیبی" معمولی به نظر بیاد و توی لحظههای درست "انتظار" رو برات انجام بده.
|
|
||||||
|
|
||||||
وقتی یه عملیاتی هست که قبل از دادن نتیجهها نیاز به انتظار داره و از این قابلیتهای جدید پایتون پشتیبانی میکنه، میتونی اینجوری کدنویسیش کنی:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
burgers = await get_burgers(2)
|
|
||||||
```
|
|
||||||
|
|
||||||
نکته کلیدی اینجا `await` هست. به پایتون میگه که باید ⏸ منتظر بمونه تا `get_burgers(2)` کارش 🕙 تموم بشه قبل از اینکه نتیجهها رو توی `burgers` ذخیره کنه. با این، پایتون میدونه که میتونه بره یه کار دیگه 🔀 ⏯ توی این مدت بکنه (مثل گرفتن یه درخواست دیگه).
|
|
||||||
|
|
||||||
برای اینکه `await` کار کنه، باید توی یه تابع باشه که از این ناهمزمانی پشتیبانی کنه. برای این کار، فقط با `async def` تعریفش میکنی:
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
async def get_burgers(number: int):
|
|
||||||
# یه سری کار ناهمزمان برای ساختن برگرها انجام بده
|
|
||||||
return burgers
|
|
||||||
```
|
|
||||||
|
|
||||||
...به جای `def`:
|
|
||||||
|
|
||||||
```Python hl_lines="2"
|
|
||||||
# این ناهمزمان نیست
|
|
||||||
def get_sequential_burgers(number: int):
|
|
||||||
# یه سری کار ترتیبی برای ساختن برگرها انجام بده
|
|
||||||
return burgers
|
|
||||||
```
|
|
||||||
|
|
||||||
با `async def`، پایتون میدونه که توی اون تابع باید حواسش به عبارتهای `await` باشه، و میتونه اجرای اون تابع رو "موقتاً متوقف" ⏸ کنه و بره یه کار دیگه 🔀 قبل از برگشتن بکنه.
|
|
||||||
|
|
||||||
وقتی میخوای یه تابع `async def` رو صدا کنی، باید "منتظرش" بمونی. پس این کار نمیکنه:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
# این کار نمیکنه، چون get_burgers با async def تعریف شده
|
|
||||||
burgers = get_burgers(2)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
پس، اگه از یه کتابخونه استفاده میکنی که بهت میگه میتونی با `await` صداش کنی، باید *توابع عملیات مسیرت* که ازش استفاده میکنن رو با `async def` بسازی، مثل:
|
|
||||||
|
|
||||||
```Python hl_lines="2-3"
|
|
||||||
@app.get('/burgers')
|
|
||||||
async def read_burgers():
|
|
||||||
burgers = await get_burgers(2)
|
|
||||||
return burgers
|
|
||||||
```
|
|
||||||
|
|
||||||
### جزئیات فنیتر
|
|
||||||
|
|
||||||
شاید متوجه شده باشی که `await` فقط توی توابعی که با `async def` تعریف شدن میتونه استفاده بشه.
|
|
||||||
|
|
||||||
ولی در عین حال، توابعی که با `async def` تعریف شدن باید "منتظر"شون بمونی. پس توابع با `async def` فقط توی توابعی که با `async def` تعریف شدن میتونن صدا زده بشن.
|
|
||||||
|
|
||||||
حالا، قضیه مرغ و تخممرغ چیه، چطور اولین تابع `async` رو صدا میکنی؟
|
|
||||||
|
|
||||||
اگه با **FastAPI** کار میکنی، لازم نیست نگران این باشی، چون اون "اولین" تابع، *تابع عملیات مسیرت* هست، و FastAPI میدونه چطور کار درست رو بکنه.
|
|
||||||
|
|
||||||
ولی اگه بخوای بدون FastAPI از `async` / `await` استفاده کنی، اینم ممکنه.
|
|
||||||
|
|
||||||
### کد ناهمزمان خودت رو بنویس
|
|
||||||
|
|
||||||
Starlette (و **FastAPI**) بر پایه <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> هستن، که باعث میشه با کتابخونه استاندارد پایتون <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> و <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a> سازگار باشه.
|
|
||||||
|
|
||||||
بهخصوص، میتونی مستقیماً از <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> برای موارد استفاده پیشرفته همزمانی که نیاز به الگوهای پیچیدهتر توی کد خودت دارن استفاده کنی.
|
|
||||||
|
|
||||||
و حتی اگه از FastAPI استفاده نکنی، میتونی برنامههای ناهمزمان خودت رو با <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> بنویسی تا خیلی سازگار باشه و فوایدش رو بگیری (مثل *همزمانی ساختاریافته*).
|
|
||||||
|
|
||||||
من یه کتابخونه دیگه روی AnyIO ساختم، یه لایه نازک روش، تا یه کم annotationهای نوع رو بهتر کنم و **تکمیل خودکار** بهتر، **خطاهای درونخطی** و غیره بگیرم. یه مقدمه و آموزش ساده هم داره که بهت کمک میکنه **بفهمی** و **کد ناهمزمان خودت رو بنویسی**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. اگه بخوای **کد ناهمزمان رو با کد معمولی** (بلاککننده/همزمان) ترکیب کنی خیلی بهدردت میخوره.
|
|
||||||
|
|
||||||
### شکلهای دیگه کد ناهمزمان
|
|
||||||
|
|
||||||
این سبک استفاده از `async` و `await` توی زبون نسبتاً جدیده.
|
|
||||||
|
|
||||||
ولی کار با کد ناهمزمان رو خیلی سادهتر میکنه.
|
|
||||||
|
|
||||||
همین سینتکس (یا تقریباً یکسان) اخیراً توی نسخههای مدرن جاوااسکریپت (توی مرورگر و NodeJS) هم اضافه شده.
|
|
||||||
|
|
||||||
ولی قبل از اون، مدیریت کد ناهمزمان خیلی پیچیدهتر و سختتر بود.
|
|
||||||
|
|
||||||
توی نسخههای قبلی پایتون، میتونستی از نخها یا <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a> استفاده کنی. ولی کد خیلی پیچیدهتر میشه برای فهمیدن، دیباگ کردن و فکر کردن بهش.
|
|
||||||
|
|
||||||
توی نسخههای قبلی NodeJS / جاوااسکریپت مرورگر، از "کالبکها" استفاده میکردی. که میرسید به "جهان کالبکها".
|
|
||||||
|
|
||||||
## کروتینها
|
|
||||||
|
|
||||||
**کروتین** فقط یه اصطلاح خیلی شیک برای چیزیه که یه تابع `async def` برمیگردونه. پایتون میدونه که این یه چیزی مثل تابع هست، میتونه شروع بشه و یه جایی تموم بشه، ولی ممکنه داخلش هم موقف ⏸ بشه، هر وقت یه `await` توش باشه.
|
|
||||||
|
|
||||||
ولی همه این قابلیت استفاده از کد ناهمزمان با `async` و `await` خیلی وقتا خلاصه میشه به استفاده از "کروتینها". این قابل مقایسه با ویژگی اصلی Go، یعنی "Goroutineها" هست.
|
|
||||||
|
|
||||||
## نتیجهگیری
|
|
||||||
|
|
||||||
بیاید همون جمله از بالا رو ببینیم:
|
|
||||||
|
|
||||||
> نسخههای مدرن پایتون از **"کد ناهمزمان"** با چیزی که بهش **"کروتین"** میگن پشتیبانی میکنن، با سینتکس **`async` و `await`**.
|
|
||||||
|
|
||||||
حالا باید بیشتر برات معنی بده. ✨
|
|
||||||
|
|
||||||
همه اینا چیزیه که به FastAPI (از طریق Starlette) قدرت میده و باعث میشه عملکرد چشمگیری داشته باشه.
|
|
||||||
|
|
||||||
## جزئیات خیلی فنی
|
|
||||||
|
|
||||||
/// warning
|
|
||||||
|
|
||||||
احتمالاً میتونی اینو رد کنی.
|
|
||||||
|
|
||||||
اینا جزئیات خیلی فنی از نحوه کار **FastAPI** زیر پوستهست.
|
|
||||||
|
|
||||||
اگه یه کم دانش فنی (کروتینها، نخها، بلاک کردن و غیره) داری و کنجکاوی که FastAPI چطور `async def` رو در مقابل `def` معمولی مدیریت میکنه، ادامه بده.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
### توابع عملیات مسیر
|
|
||||||
|
|
||||||
وقتی یه *تابع عملیات مسیر* رو با `def` معمولی به جای `async def` تعریف میکنی، توی یه استخر نخ خارجی اجرا میشه که بعدش منتظرش میمونن، به جای اینکه مستقیم صداش کنن (چون سرور رو بلاک میکنه).
|
|
||||||
|
|
||||||
اگه از یه فریمورک ناهمزمان دیگه میای که به روش بالا کار نمیکنه و عادت داری *توابع عملیات مسیر* ساده فقط محاسباتی رو با `def` معمولی برای یه سود کوچیک عملکرد (حدود 100 نانوثانیه) تعریف کنی، توجه کن که توی **FastAPI** اثرش کاملاً برعکسه. توی این موارد، بهتره از `async def` استفاده کنی مگه اینکه *توابع عملیات مسیرت* کدی داشته باشن که عملیات <abbr title="ورودی/خروجی: خوندن یا نوشتن دیسک، ارتباطات شبکه">I/O</abbr> بلاککننده انجام بده.
|
|
||||||
|
|
||||||
با این حال، توی هر دو موقعیت، احتمالش زیاده که **FastAPI** هنوز [سریعتر](index.md#performance){.internal-link target=_blank} از فریمورک قبلیات باشه (یا حداقل قابل مقایسه باهاش).
|
|
||||||
|
|
||||||
### وابستگیها
|
|
||||||
|
|
||||||
همین برای [وابستگیها](tutorial/dependencies/index.md){.internal-link target=_blank} هم صدق میکنه. اگه یه وابستگی یه تابع `def` معمولی به جای `async def` باشه، توی استخر نخ خارجی اجرا میشه.
|
|
||||||
|
|
||||||
### زیروابستگیها
|
|
||||||
|
|
||||||
میتونی چند تا وابستگی و [زیروابستگی](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} داشته باشی که همدیگه رو نیاز دارن (بهعنوان پارامترهای تعریف تابع)، بعضیهاشون ممکنه با `async def` ساخته بشن و بعضیها با `def` معمولی. بازم کار میکنه، و اونایی که با `def` معمولی ساخته شدن توی یه نخ خارجی (از استخر نخ) صدا زده میشن به جای اینکه "منتظرشون" بمونن.
|
|
||||||
|
|
||||||
### توابع کاربردی دیگه
|
|
||||||
|
|
||||||
هر تابع کاربردی دیگهای که مستقیم خودت صداش میکنی میتونه با `def` معمولی یا `async def` ساخته بشه و FastAPI رو نحوه صدازدنش تأثیر نمیذاره.
|
|
||||||
|
|
||||||
این برخلاف توابعی هست که FastAPI برات صداشون میکنه: *توابع عملیات مسیر* و وابستگیها.
|
|
||||||
|
|
||||||
اگه تابع کاربردیت یه تابع معمولی با `def` باشه، مستقیم صداش میکنن (همونطور که توی کدت نوشتی)، نه توی استخر نخ، اگه تابع با `async def` ساخته شده باشه، باید وقتی توی کدت صداش میکنی `await`ش کنی.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
دوباره، اینا جزئیات خیلی فنی هستن که احتمالاً اگه دنبالشون اومده باشی برات مفید باشن.
|
|
||||||
|
|
||||||
وگرنه، با راهنماییهای بخش بالا باید خوب باشی: <a href="#in-a-hurry">عجله داری؟</a>.
|
|
||||||
|
|
@ -1,298 +0,0 @@
|
||||||
# متغیرهای محیطی
|
|
||||||
|
|
||||||
/// tip
|
|
||||||
|
|
||||||
اگه از قبل میدونی متغیرهای محیطی چی هستن و چطور ازشون استفاده میشه، میتونی این بخش رو رد کنی.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
یه متغیر محیطی (که بهش "**env var**" هم میگن) یه متغیریه که **خارج** از کد پایتون، توی **سیستمعامل** زندگی میکنه و میتونه توسط کد پایتونت (یا برنامههای دیگه) خونده بشه.
|
|
||||||
|
|
||||||
متغیرهای محیطی میتونن برای مدیریت **تنظیمات** برنامه، بهعنوان بخشی از **نصب** پایتون و غیره مفید باشن.
|
|
||||||
|
|
||||||
## ساخت و استفاده از متغیرهای محیطی
|
|
||||||
|
|
||||||
میتونی متغیرهای محیطی رو توی **شل (ترمینال)** **بسازی** و ازشون استفاده کنی، بدون اینکه به پایتون نیاز داشته باشی:
|
|
||||||
|
|
||||||
//// tab | لینوکس، مکاواس، ویندوز بش
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
// میتونی یه متغیر محیطی به اسم MY_NAME بسازی با
|
|
||||||
$ export MY_NAME="Wade Wilson"
|
|
||||||
|
|
||||||
// بعد میتونی با برنامههای دیگه ازش استفاده کنی، مثل
|
|
||||||
$ echo "Hello $MY_NAME"
|
|
||||||
|
|
||||||
Hello Wade Wilson
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | ویندوز پاورشل
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
// یه متغیر محیطی به اسم MY_NAME بساز
|
|
||||||
$ $Env:MY_NAME = "Wade Wilson"
|
|
||||||
|
|
||||||
// با برنامههای دیگه ازش استفاده کن، مثل
|
|
||||||
$ echo "Hello $Env:MY_NAME"
|
|
||||||
|
|
||||||
Hello Wade Wilson
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
## خوندن متغیرهای محیطی توی پایتون
|
|
||||||
|
|
||||||
میتونی متغیرهای محیطی رو **خارج** از پایتون، توی ترمینال (یا با هر روش دیگه) بسازی، و بعد توی **پایتون** اونا رو بخونی.
|
|
||||||
|
|
||||||
مثلاً میتونی یه فایل `main.py` داشته باشی با:
|
|
||||||
|
|
||||||
```Python hl_lines="3"
|
|
||||||
import os
|
|
||||||
|
|
||||||
name = os.getenv("MY_NAME", "World")
|
|
||||||
print(f"Hello {name} from Python")
|
|
||||||
```
|
|
||||||
|
|
||||||
/// tip
|
|
||||||
|
|
||||||
آرگومان دوم <a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> مقدار پیشفرضیه که برمیگردونه.
|
|
||||||
|
|
||||||
اگه ندی، بهصورت پیشفرض `None` هست، اینجا ما `"World"` رو بهعنوان مقدار پیشفرض گذاشتیم.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
بعد میتونی اون برنامه پایتون رو صدا کنی:
|
|
||||||
|
|
||||||
//// tab | لینوکس، مکاواس، ویندوز بش
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
// اینجا هنوز متغیر محیطی رو تنظیم نکردیم
|
|
||||||
$ python main.py
|
|
||||||
|
|
||||||
// چون متغیر محیطی رو تنظیم نکردیم، مقدار پیشفرض رو میگیریم
|
|
||||||
|
|
||||||
Hello World from Python
|
|
||||||
|
|
||||||
// ولی اگه اول یه متغیر محیطی بسازیم
|
|
||||||
$ export MY_NAME="Wade Wilson"
|
|
||||||
|
|
||||||
// و بعد دوباره برنامه رو صدا کنیم
|
|
||||||
$ python main.py
|
|
||||||
|
|
||||||
// حالا میتونه متغیر محیطی رو بخونه
|
|
||||||
|
|
||||||
Hello Wade Wilson from Python
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | ویندوز پاورشل
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
// اینجا هنوز متغیر محیطی رو تنظیم نکردیم
|
|
||||||
$ python main.py
|
|
||||||
|
|
||||||
// چون متغیر محیطی رو تنظیم نکردیم، مقدار پیشفرض رو میگیریم
|
|
||||||
|
|
||||||
Hello World from Python
|
|
||||||
|
|
||||||
// ولی اگه اول یه متغیر محیطی بسازیم
|
|
||||||
$ $Env:MY_NAME = "Wade Wilson"
|
|
||||||
|
|
||||||
// و بعد دوباره برنامه رو صدا کنیم
|
|
||||||
$ python main.py
|
|
||||||
|
|
||||||
// حالا میتونه متغیر محیطی رو بخونه
|
|
||||||
|
|
||||||
Hello Wade Wilson from Python
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
چون متغیرهای محیطی میتونن خارج از کد تنظیم بشن، ولی کد میتونه اونا رو بخونه، و لازم نیست با بقیه فایلها ذخیره (کمیتی به `git`) بشن، معمولاً برای پیکربندی یا **تنظیمات** استفاده میشن.
|
|
||||||
|
|
||||||
همچنین میتونی یه متغیر محیطی رو فقط برای **یه اجرای خاص برنامه** بسازی، که فقط برای اون برنامه و فقط برای مدت زمان اجراش در دسترسه.
|
|
||||||
|
|
||||||
برای این کار، درست قبل از خود برنامه، توی همون خط بسازش:
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
// یه متغیر محیطی MY_NAME رو توی خط برای این اجرای برنامه بساز
|
|
||||||
$ MY_NAME="Wade Wilson" python main.py
|
|
||||||
|
|
||||||
// حالا میتونه متغیر محیطی رو بخونه
|
|
||||||
|
|
||||||
Hello Wade Wilson from Python
|
|
||||||
|
|
||||||
// متغیر محیطی بعدش دیگه وجود نداره
|
|
||||||
$ python main.py
|
|
||||||
|
|
||||||
Hello World from Python
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
/// tip
|
|
||||||
|
|
||||||
میتونی بیشتر در موردش توی <a href="https://12factor.net/config" class="external-link" target="_blank">برنامه دوازدهفاکتوری: پیکربندی</a> بخونی.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## نوعها و اعتبارسنجی
|
|
||||||
|
|
||||||
این متغیرهای محیطی فقط میتونن **رشتههای متنی** رو نگه دارن، چون خارج از پایتون هستن و باید با برنامههای دیگه و بقیه سیستم (و حتی سیستمعاملهای مختلف مثل لینوکس، ویندوز، مکاواس) سازگار باشن.
|
|
||||||
|
|
||||||
یعنی **هر مقداری** که توی پایتون از یه متغیر محیطی خونده میشه یه `str` هست، و هر تبدیل به نوع دیگه یا هر اعتبارسنجی باید توی کد انجام بشه.
|
|
||||||
|
|
||||||
توی [راهنمای کاربر پیشرفته - تنظیمات و متغیرهای محیطی](./advanced/settings.md){.internal-link target=_blank} بیشتر در مورد استفاده از متغیرهای محیطی برای مدیریت **تنظیمات برنامه** یاد میگیری.
|
|
||||||
|
|
||||||
## متغیر محیطی `PATH`
|
|
||||||
|
|
||||||
یه متغیر محیطی **خاص** به اسم **`PATH`** وجود داره که سیستمعاملها (لینوکس، مکاواس، ویندوز) ازش برای پیدا کردن برنامههایی که قراره اجرا بشن استفاده میکنن.
|
|
||||||
|
|
||||||
مقدار متغیر `PATH` یه رشته طولانی از پوشههاست که توی لینوکس و مکاواس با دونقطه `:` و توی ویندوز با نقطهویرگول `;` از هم جدا شدن.
|
|
||||||
|
|
||||||
مثلاً، متغیر محیطی `PATH` میتونه اینجوری باشه:
|
|
||||||
|
|
||||||
//// tab | لینوکس، مکاواس
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
||||||
```
|
|
||||||
|
|
||||||
یعنی سیستم باید دنبال برنامهها توی این پوشهها بگرده:
|
|
||||||
|
|
||||||
* `/usr/local/bin`
|
|
||||||
* `/usr/bin`
|
|
||||||
* `/bin`
|
|
||||||
* `/usr/sbin`
|
|
||||||
* `/sbin`
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | ویندوز
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
|
|
||||||
```
|
|
||||||
|
|
||||||
یعنی سیستم باید دنبال برنامهها توی این پوشهها بگرده:
|
|
||||||
|
|
||||||
* `C:\Program Files\Python312\Scripts`
|
|
||||||
* `C:\Program Files\Python312`
|
|
||||||
* `C:\Windows\System32`
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
وقتی یه **دستور** توی ترمینال تایپ میکنی، سیستمعامل **دنبال** برنامه توی **هر کدوم از این پوشهها** که توی متغیر محیطی `PATH` لیست شدن میگرده.
|
|
||||||
|
|
||||||
مثلاً، وقتی توی ترمینال `python` تایپ میکنی، سیستمعامل دنبال یه برنامه به اسم `python` توی **اولین پوشه** توی اون لیست میگرده.
|
|
||||||
|
|
||||||
اگه پیداش کنه، **استفادهش میکنه**. وگرنه توی **پوشههای بعدی** دنبالش میگرده.
|
|
||||||
|
|
||||||
### نصب پایتون و بهروزرسانی `PATH`
|
|
||||||
|
|
||||||
وقتی پایتون رو نصب میکنی، ممکنه ازت بپرسن آیا میخوای متغیر محیطی `PATH` رو بهروزرسانی کنی.
|
|
||||||
|
|
||||||
//// tab | لینوکس، مکاواس
|
|
||||||
|
|
||||||
فرض کن پایتون رو نصب کردی و توی یه پوشه `/opt/custompython/bin` قرار گرفته.
|
|
||||||
|
|
||||||
اگه بگی بله برای بهروزرسانی متغیر محیطی `PATH`، نصاب `/opt/custompython/bin` رو به متغیر محیطی `PATH` اضافه میکنه.
|
|
||||||
|
|
||||||
ممکنه اینجوری بشه:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
|
|
||||||
```
|
|
||||||
|
|
||||||
اینجوری، وقتی توی ترمینال `python` تایپ میکنی، سیستم برنامه پایتون رو توی `/opt/custompython/bin` (آخرین پوشه) پیدا میکنه و از اون استفاده میکنه.
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | ویندوز
|
|
||||||
|
|
||||||
فرض کن پایتون رو نصب کردی و توی یه پوشه `C:\opt\custompython\bin` قرار گرفته.
|
|
||||||
|
|
||||||
اگه بگی بله برای بهروزرسانی متغیر محیطی `PATH`، نصاب `C:\opt\custompython\bin` رو به متغیر محیطی `PATH` اضافه میکنه.
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
|
|
||||||
```
|
|
||||||
|
|
||||||
اینجوری، وقتی توی ترمینال `python` تایپ میکنی، سیستم برنامه پایتون رو توی `C:\opt\custompython\bin` (آخرین پوشه) پیدا میکنه و از اون استفاده میکنه.
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
پس، اگه تایپ کنی:
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ python
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
//// tab | لینوکس، مکاواس
|
|
||||||
|
|
||||||
سیستم برنامه `python` رو توی `/opt/custompython/bin` **پیدا** میکنه و اجراش میکنه.
|
|
||||||
|
|
||||||
تقریباً معادل اینه که تایپ کنی:
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ /opt/custompython/bin/python
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | ویندوز
|
|
||||||
|
|
||||||
سیستم برنامه `python` رو توی `C:\opt\custompython\bin\python` **پیدا** میکنه و اجراش میکنه.
|
|
||||||
|
|
||||||
تقریباً معادل اینه که تایپ کنی:
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ C:\opt\custompython\bin\python
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
این اطلاعات وقتی در مورد [محیطهای مجازی](virtual-environments.md){.internal-link target=_blank} یاد میگیری بهدردت میخوره.
|
|
||||||
|
|
||||||
## نتیجهگیری
|
|
||||||
|
|
||||||
با این باید یه درک پایهای از **متغیرهای محیطی** و نحوه استفادهشون توی پایتون داشته باشی.
|
|
||||||
|
|
||||||
میتونی بیشتر در موردشون توی <a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">ویکیپدیا برای متغیر محیطی</a> بخونی.
|
|
||||||
|
|
||||||
توی خیلی موارد مشخص نیست که متغیرهای محیطی چطور میتونن فوری مفید و کاربردی باشن. ولی توی موقعیتهای مختلف توسعه مدام پیداشون میشه، پس خوبه که در موردشون بدونی.
|
|
||||||
|
|
||||||
مثلاً، توی بخش بعدی در مورد [محیطهای مجازی](virtual-environments.md) به این اطلاعات نیاز داری.
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
# ویژگی ها
|
|
||||||
|
|
||||||
## ویژگی های FastAPI
|
|
||||||
|
|
||||||
**FastAPI** موارد زیر را به شما ارائه میدهد:
|
|
||||||
|
|
||||||
### برپایه استاندارد های باز
|
|
||||||
|
|
||||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> برای ساخت API, شامل مشخص سازی <abbr title="که علاوه بر path, به عنوان endpoint و route نیز شناخته میشود">path</abbr> <abbr title="که به عنوان متودهای HTTP یعنی POST,GET,PUT,DELETE و ... شناخته میشوند">operation</abbr> ها, <abbr title="parameters">پارامترها</abbr>, body request ها, امنیت و غیره.
|
|
||||||
* مستندسازی خودکار data model با <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (همانطور که OpenAPI خود نیز مبتنی بر JSON Schema است).
|
|
||||||
* طراحی شده بر اساس استاندارد هایی که پس از یک مطالعه دقیق بدست آمده اند بجای طرحی ناپخته و بدون فکر.
|
|
||||||
* همچنین به شما اجازه میدهد تا از تولید خودکار client code در بسیاری از زبان ها استفاده کنید.
|
|
||||||
|
|
||||||
### مستندات خودکار
|
|
||||||
|
|
||||||
مستندات API تعاملی و ایجاد رابط کاربری وب. از آنجایی که این فریم ورک برپایه OpenAPI میباشد، آپشن های متعددی وجود دارد که ۲ مورد بصورت پیش فرض گنجانده شده اند.
|
|
||||||
|
|
||||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>، با <abbr title="interactive exploration">کاوش تعاملی</abbr>، API خود را مستقیما از طریق مرورگر صدازده و تست کنید.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* مستندات API جایگزین با <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### فقط پایتون مدرن
|
|
||||||
|
|
||||||
همه اینها برپایه type declaration های **پایتون ۳.۶** استاندارد (به لطف Pydantic) میباشند. سینتکس جدیدی درکار نیست. تنها پایتون مدرن استاندارد.
|
|
||||||
|
|
||||||
اگر به یک یادآوری ۲ دقیقه ای در مورد نحوه استفاده از تایپ های پایتون دارید (حتی اگر از FastAPI استفاده نمیکنید) این آموزش کوتاه را بررسی کنید: [Python Types](python-types.md){.internal-link target=\_blank}.
|
|
||||||
|
|
||||||
شما پایتون استاندارد را با استفاده از تایپ ها مینویسید:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
# Declare a variable as a str
|
|
||||||
# and get editor support inside the function
|
|
||||||
def main(user_id: str):
|
|
||||||
return user_id
|
|
||||||
|
|
||||||
|
|
||||||
# A Pydantic model
|
|
||||||
class User(BaseModel):
|
|
||||||
id: int
|
|
||||||
name: str
|
|
||||||
joined: date
|
|
||||||
```
|
|
||||||
|
|
||||||
که سپس میتوان به این شکل از آن استفاده کرد:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
|
|
||||||
|
|
||||||
second_user_data = {
|
|
||||||
"id": 4,
|
|
||||||
"name": "Mary",
|
|
||||||
"joined": "2018-11-30",
|
|
||||||
}
|
|
||||||
|
|
||||||
my_second_user: User = User(**second_user_data)
|
|
||||||
```
|
|
||||||
|
|
||||||
/// info
|
|
||||||
|
|
||||||
`**second_user_data` یعنی:
|
|
||||||
|
|
||||||
کلید ها و مقادیر دیکشنری `second_user_data` را مستقیما به عنوان ارگومان های key-value بفرست، که معادل است با : `User(id=4, name="Mary", joined="2018-11-30")`
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
### پشتیبانی ویرایشگر
|
|
||||||
|
|
||||||
تمام فریم ورک به گونه ای طراحی شده که استفاده از آن آسان و شهودی باشد، تمام تصمیمات حتی قبل از شروع توسعه بر روی چندین ویرایشگر آزمایش شده اند، تا از بهترین تجربه توسعه اطمینان حاصل شود.
|
|
||||||
|
|
||||||
در آخرین نظرسنجی توسعه دهندگان پایتون کاملا مشخص بود که <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">بیشترین ویژگی مورد استفاده از "<abbr title="autocompletion">تکمیل خودکار</abbr>" است</a>.
|
|
||||||
|
|
||||||
تمام فریم ورک **FastAPI** برپایه ای برای براورده کردن این نیاز نیز ایجاد گشته است. تکمیل خودکار در همه جا کار میکند.
|
|
||||||
|
|
||||||
شما به ندرت نیاز به بازگشت به مستندات را خواهید داشت.
|
|
||||||
|
|
||||||
ببینید که چگونه ویرایشگر شما ممکن است به شما کمک کند:
|
|
||||||
|
|
||||||
* در <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* در <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
شما پیشنهاد های تکمیل خودکاری را خواهید گرفت که حتی ممکن است قبلا آن را غیرممکن تصور میکردید. به عنوان مثال کلید `price` در داخل بدنه JSON (که میتوانست تودرتو نیز باشد) که از یک درخواست آمده است.
|
|
||||||
|
|
||||||
دیگر خبری از تایپ کلید اشتباهی، برگشتن به مستندات یا پایین بالا رفتن برای فهمیدن اینکه شما از `username` یا `user_name` استفاده کرده اید نیست.
|
|
||||||
|
|
||||||
### مختصر
|
|
||||||
|
|
||||||
FastAPI **پیش فرض** های معقولی برای همه چیز دارد، با قابلیت تنظیمات اختیاری در همه جا. تمام پارامترها را میتوانید برای انجام انچه نیاز دارید و برای تعریف API مورد نیاز خود به خوبی تنظیم کنید.
|
|
||||||
|
|
||||||
اما به طور پیش فرض، همه چیز **کار میکند**.
|
|
||||||
|
|
||||||
### اعتبارسنجی
|
|
||||||
|
|
||||||
* اعتبارسنجی برای بیشتر (یا همه؟) **data type** های پایتون، شامل:
|
|
||||||
|
|
||||||
* JSON objects (`dict`)
|
|
||||||
* آرایه های (`list`) JSON با قابلیت مشخص سازی تایپ ایتم های درون لیست.
|
|
||||||
* فیلد های رشته (`str`)، به همراه مشخص سازی حداقل و حداکثر طول رشته.
|
|
||||||
* اعداد (`int`,`float`) با حداقل و حداکثر مقدار و غیره.
|
|
||||||
|
|
||||||
* اعتبارسنجی برای تایپ های عجیب تر، مثل:
|
|
||||||
* URL.
|
|
||||||
* Email.
|
|
||||||
* UUID.
|
|
||||||
* و غیره.
|
|
||||||
|
|
||||||
تمام اعتبارسنجی ها توسط کتابخانه اثبات شده و قدرتمند **Pydantic** انجام میشود.
|
|
||||||
|
|
||||||
### <abbr title="Security and authentication">امنیت و احراز هویت</abbr>
|
|
||||||
|
|
||||||
امنیت و احرازهویت بدون هیچگونه ارتباط و مصالحه ای با پایگاه های داده یا مدل های داده ایجاد شده اند.
|
|
||||||
|
|
||||||
تمام طرح های امنیتی در OpenAPI تعریف شده اند، از جمله:
|
|
||||||
|
|
||||||
* .
|
|
||||||
* **OAuth2** (همچنین با **JWT tokens**). آموزش را در [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=\_blank} مشاهده کنید.
|
|
||||||
* کلید های API:
|
|
||||||
* <abbr title="سرصفحه ها">Headers</abbr>
|
|
||||||
* <abbr title="پارامترهای پرسمان">Query parameters</abbr>
|
|
||||||
* <abbr title="کوکی ها">Cookies</abbr>، و غیره.
|
|
||||||
|
|
||||||
به علاوه تمام ویژگی های امنیتی از **Statlette** (شامل **<abbr title="کوکی های جلسه">session cookies</abbr>**)
|
|
||||||
|
|
||||||
همه اینها به عنوان ابزارها و اجزای قابل استفاده ای ساخته شده اند که به راحتی با سیستم های شما، مخازن داده، پایگاه های داده رابطه ای و NoSQL و غیره ادغام میشوند.
|
|
||||||
|
|
||||||
### <abbr title="تزریق وابستگی">Dependency Injection</abbr>
|
|
||||||
|
|
||||||
FastAPI شامل یک سیستم <abbr title='همچنین به عنوان "components", "resources", "services" و "providers" شناخته میشود'><strong>Dependency Injection</strong></abbr> بسیار آسان اما بسیار قدرتمند است.
|
|
||||||
|
|
||||||
* حتی وابستگی ها نیز میتوانند وابستگی هایی داشته باشند و یک سلسله مراتب یا **"گرافی" از وابستگی ها** ایجاد کنند.
|
|
||||||
|
|
||||||
* همه چیز توسط فریم ورک **به طور خودکار اداره میشود**
|
|
||||||
|
|
||||||
* همه وابستگی ها میتوانند به داده های request ها نیاز داشته باشند و مستندات خودکار و محدودیت های <abbr title="عملیات مسیر">path operation</abbr> را **افزایش** دهند.
|
|
||||||
|
|
||||||
* با قابلیت **اعتبارسنجی خودکار** حتی برای path operation parameter های تعریف شده در وابستگی ها.
|
|
||||||
|
|
||||||
* پشتیبانی از سیستم های پیچیده احرازهویت کاربر، **اتصالات پایگاه داده** و غیره.
|
|
||||||
|
|
||||||
* بدون هیچ ارتباطی با دیتابیس ها، فرانت اند و غیره. اما ادغام آسان و راحت با همه آنها.
|
|
||||||
|
|
||||||
### پلاگین های نامحدود
|
|
||||||
|
|
||||||
یا به عبارت دیگر، هیچ نیازی به آنها نیست، کد موردنیاز خود را وارد و استفاده کنید.
|
|
||||||
|
|
||||||
هر یکپارچه سازی به گونه ای طراحی شده است که استفاده از آن بسیار ساده باشد (با وابستگی ها) که میتوانید با استفاده از همان ساختار و روشی که برای _path operation_ های خود استفاده کرده اید تنها در ۲ خط کد "پلاگین" برنامه خودتان را ایجاد کنید.
|
|
||||||
|
|
||||||
### تست شده
|
|
||||||
|
|
||||||
* 100% <abbr title="مقدار کدی که به طور خودکار تست شده است">پوشش تست</abbr>.
|
|
||||||
|
|
||||||
* 100% کد بر اساس <abbr title="حاشیه نویسی تایپ های پایتون (Python type annotations)، با استفاده از آن ویرایشگر و ابزارهای خارجی شما می توانند پشتیبانی بهتری از شما ارائه دهند">type annotate ها</abbr>.
|
|
||||||
|
|
||||||
* استفاده شده در اپلیکیشن های تولید
|
|
||||||
|
|
||||||
## ویژگی های Starlette
|
|
||||||
|
|
||||||
**FastAPI** کاملا (و براساس) با <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a> سازگار است. بنابراین، هرکد اضافی Starlette که دارید، نیز کار خواهد کرد.
|
|
||||||
|
|
||||||
`FastAPI` در واقع یک زیرکلاس از `Starlette` است. بنابراین اگر از قبل Starlette را میشناسید یا با آن کار کرده اید، بیشتر قابلیت ها به همین روش کار خواهد کرد.
|
|
||||||
|
|
||||||
با **FastAPI** شما تمام ویژگی های **Starlette** را خواهید داشت (زیرا FastAPI یک نسخه و نمونه به تمام معنا از Starlette است):
|
|
||||||
|
|
||||||
* عملکرد به طورجدی چشمگیر. <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">این یکی از سریعترین فریم ورک های موجود در پایتون است که همتراز با **نود جی اس** و **گو**</a> است.
|
|
||||||
* پشتیبانی از **WebSocket**.
|
|
||||||
* <abbr title="In-process background tasks">تسک های درجریان در پس زمینه</abbr>.
|
|
||||||
* <abbr title="Startup and shutdown events">رویداد های راه اندازی و متوفق شدن<abbr>.
|
|
||||||
* تست کلاینت ساخته شده به روی HTTPX.
|
|
||||||
* **CORS**, GZip, فایل های استاتیک, <abbr title="Streaming responses">پاسخ های جریانی</abbr>.
|
|
||||||
* پشتیبانی از **نشست ها و کوکی ها**.
|
|
||||||
* 100% پوشش با تست.
|
|
||||||
* 100% کد براساس type annotate ها.
|
|
||||||
|
|
||||||
## ویژگی های Pydantic
|
|
||||||
|
|
||||||
**FastAPI** کاملا (و براساس) با <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a> سازگار است. بنابراین هرکد Pydantic اضافی که داشته باشید، نیز کار خواهد کرد.
|
|
||||||
|
|
||||||
از جمله کتابخانه های خارجی نیز مبتنی بر Pydantic میتوان به <abbr title="Object-Relational Mapper">ORM</abbr> و <abbr title="Object-Document Mapper">ODM</abbr> ها برای دیتابیس ها اشاره کرد.
|
|
||||||
|
|
||||||
این همچنین به این معناست که در خیلی از موارد میتوانید همان ابجکتی که از request میگیرید را **مستقیما به دیتابیس** بفرستید زیرا همه چیز به طور خودکار تأیید میشود.
|
|
||||||
|
|
||||||
همین امر برعکس نیز صدق میکند، در بسیاری از موارد شما میتوانید ابجکتی را که از پایگاه داده دریافت میکنید را **مستقیماً به کاربر** ارسال کنید.
|
|
||||||
|
|
||||||
با FastAPI شما تمام ویژگی های Pydantic را دراختیار دارید (زیرا FastAPI برای تمام بخش مدیریت دیتا بر اساس Pydantic عمل میکند):
|
|
||||||
|
|
||||||
* **خبری از گیج شدن نیست**:
|
|
||||||
* هیچ <abbr title="micro-language">زبان خردی</abbr> برای یادگیری تعریف طرحواره های جدید وجود ندارد.
|
|
||||||
* اگر تایپ های پایتون را میشناسید، نحوه استفاده از Pydantic را نیز میدانید.
|
|
||||||
* به خوبی با **<abbr title="همان Integrated Development Environment, شبیه به ویرایشگر کد">IDE</abbr>/<abbr title="برنامه ای که خطاهای کد را بررسی می کند">linter</abbr>/مغز** شما عمل میکند:
|
|
||||||
* به این دلیل که ساختار داده Pydantic فقط نمونه هایی از کلاس هایی هستند که شما تعریف میکنید، تکمیل خودکار، mypy، linting و مشاهده شما باید به درستی با داده های معتبر شما کار کنند.
|
|
||||||
* اعتبار سنجی **ساختارهای پیچیده**:
|
|
||||||
* استفاده از مدل های سلسله مراتبی Pydantic, `List` و `Dict` کتابخانه `typing` پایتون و غیره.
|
|
||||||
* و اعتبارسنج ها اجازه میدهند که طرحواره های داده پیچیده به طور واضح و آسان تعریف، بررسی و بر پایه JSON مستند شوند.
|
|
||||||
* شما میتوانید ابجکت های عمیقا تودرتو JSON را که همگی تایید شده و annotated شده اند را داشته باشید.
|
|
||||||
* **قابل توسعه**:
|
|
||||||
* Pydantic اجازه میدهد تا data type های سفارشی تعریف شوند یا میتوانید اعتبارسنجی را با روش هایی به روی مدل ها با <abbr title="دکوریتور های اعتبارسنج">validator decorator</abbr> گسترش دهید.
|
|
||||||
* 100% پوشش با تست.
|
|
||||||
|
|
@ -1,467 +0,0 @@
|
||||||
# FastAPI
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.md-content .md-typeset h1 { display: none; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<em>فریمورک FastAPI، کارایی بالا، یادگیری آسان، کدنویسی سریع، آماده برای استفاده در محیط پروداکشن</em>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
|
||||||
<img src="https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master" alt="Test">
|
|
||||||
</a>
|
|
||||||
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi" target="_blank">
|
|
||||||
<img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg" alt="Coverage">
|
|
||||||
</a>
|
|
||||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
|
||||||
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
|
|
||||||
</a>
|
|
||||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
|
||||||
<img src="https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058" alt="Supported Python versions">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**مستندات**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
|
||||||
|
|
||||||
**کد منبع**: <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
|
||||||
|
|
||||||
---
|
|
||||||
FastAPI یک وب فریمورک مدرن و سریع (با کارایی بالا) برای ایجاد APIهای متنوع (وب، وبسوکت و غبره) با زبان پایتون نسخه +۳.۶ است. این فریمورک با رعایت کامل راهنمای نوع داده (Type Hint) ایجاد شده است.
|
|
||||||
|
|
||||||
ویژگیهای کلیدی این فریمورک عبارتند از:
|
|
||||||
|
|
||||||
* **<abbr title="Fast">سرعت</abbr>**: کارایی بسیار بالا و قابل مقایسه با **NodeJS** و **Go** (با تشکر از Starlette و Pydantic). [یکی از سریعترین فریمورکهای پایتونی موجود](#_10).
|
|
||||||
|
|
||||||
* **<abbr title="Fast to code">کدنویسی سریع</abbr>**: افزایش ۲۰۰ تا ۳۰۰ درصدی سرعت توسعه قابلیتهای جدید. *
|
|
||||||
* **<abbr title="Fewer bugs">باگ کمتر</abbr>**: کاهش ۴۰ درصدی خطاهای انسانی (برنامهنویسی). *
|
|
||||||
* **<abbr title="Intuitive">هوشمندانه</abbr>**: پشتیبانی فوقالعاده در محیطهای توسعه یکپارچه (IDE). <abbr title="یا اتوکامپلیت، اتوکامپلشن، اینتلیسنس">تکمیل</abbr> در همه بخشهای کد. کاهش زمان رفع باگ.
|
|
||||||
* **<abbr title="Easy">آسان</abbr>**: طراحی شده برای یادگیری و استفاده آسان. کاهش زمان مورد نیاز برای مراجعه به مستندات.
|
|
||||||
* **<abbr title="Short">کوچک</abbr>**: کاهش تکرار در کد. چندین قابلیت برای هر پارامتر (منظور پارامترهای ورودی تابع هندلر میباشد، به بخش <a href="https://fastapi.tiangolo.com/#recap">خلاصه</a> در همین صفحه مراجعه شود). باگ کمتر.
|
|
||||||
* **<abbr title="Robust">استوار</abbr>**: ایجاد کدی آماده برای استفاده در محیط پروداکشن و تولید خودکار <abbr title="Interactive documentation">مستندات تعاملی</abbr>
|
|
||||||
* **<abbr title="Standards-based">مبتنی بر استانداردها</abbr>**: مبتنی بر (و منطبق با) استانداردهای متن باز مربوط به API: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (سوگر سابق) و <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
|
||||||
|
|
||||||
<small>* تخمینها بر اساس تستهای انجام شده در یک تیم توسعه داخلی که مشغول ایجاد برنامههای کاربردی واقعی بودند صورت گرفته است.</small>
|
|
||||||
|
|
||||||
## اسپانسرهای طلایی
|
|
||||||
|
|
||||||
<!-- sponsors -->
|
|
||||||
|
|
||||||
{% if sponsors %}
|
|
||||||
{% for sponsor in sponsors.gold -%}
|
|
||||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- /sponsors -->
|
|
||||||
|
|
||||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">دیگر اسپانسرها</a>
|
|
||||||
|
|
||||||
## نظر دیگران در مورد FastAPI
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;"><em> [...] I'm using <strong>FastAPI</strong> a ton these days. [...] I'm actually planning to use it for all of my team's <strong>ML services at Microsoft</strong>. Some of them are getting integrated into the core <strong>Windows</strong> product and some <strong>Office</strong> products."</em></div>
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;"><em>"We adopted the <strong>FastAPI</strong> library to spawn a <strong>REST</strong>server that can be queried to obtain <strong>predictions</strong>. [for Ludwig]"</em></div>
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;">"<strong>Netflix</strong> is pleased to announce the open-source release of our <strong>crisis management</strong> orchestration framework: <strong>Dispatch</strong>! [built with <strong>FastAPI</strong>]"</div>
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;">"<em>I’m over the moon excited about <strong>FastAPI</strong>. It’s so fun!"</em></div>
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;">"<em>Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted <strong>Hug</strong> to be - it's really inspiring to see someone build that."</em></div>
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;">"<em>If you're looking to learn one <strong>modern framework</strong> for building REST APIs, check out <strong>FastAPI</strong> [...] It's fast, easy to use and easy to learn [...]"</em></div>
|
|
||||||
|
|
||||||
<div style="text-align: left; direction: ltr;">"<em>We've switched over to <strong>FastAPI</strong> for our <strong>APIs</strong> [...] I think you'll like it [...]</em>"</div>
|
|
||||||
|
|
||||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## **Typer**, فریمورکی معادل FastAPI برای کار با <abbr title="CLI (Command Line Interface)">واسط خط فرمان</abbr>
|
|
||||||
|
|
||||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
|
||||||
|
|
||||||
اگر در حال ساختن برنامهای برای استفاده در <abbr title="Command Line Interface">CLI</abbr> (به جای استفاده در وب) هستید، میتوانید از <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>. استفاده کنید.
|
|
||||||
|
|
||||||
**Typer** دوقلوی کوچکتر FastAPI است و قرار است معادلی برای FastAPI در برنامههای CLI باشد.️ 🚀
|
|
||||||
|
|
||||||
## نیازمندیها
|
|
||||||
|
|
||||||
پایتون +۳.۶
|
|
||||||
|
|
||||||
FastAPI مبتنی بر ابزارهای قدرتمند زیر است:
|
|
||||||
|
|
||||||
* فریمورک <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> برای بخش وب.
|
|
||||||
* کتابخانه <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> برای بخش داده.
|
|
||||||
|
|
||||||
## نصب
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ pip install fastapi
|
|
||||||
|
|
||||||
---> 100%
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
نصب یک سرور پروداکشن نظیر <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> یا <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a> نیز جزء نیازمندیهاست.
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ pip install "uvicorn[standard]"
|
|
||||||
|
|
||||||
---> 100%
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## مثال
|
|
||||||
|
|
||||||
### ایجاد کنید
|
|
||||||
* فایلی به نام `main.py` با محتوای زیر ایجاد کنید:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from fastapi import FastAPI
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
def read_root():
|
|
||||||
return {"Hello": "World"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
|
||||||
def read_item(item_id: int, q: Union[str, None] = None):
|
|
||||||
return {"item_id": item_id, "q": q}
|
|
||||||
```
|
|
||||||
|
|
||||||
<details markdown="1">
|
|
||||||
<summary>همچنین میتوانید از <code>async def</code>... نیز استفاده کنید</summary>
|
|
||||||
|
|
||||||
اگر در کدتان از `async` / `await` استفاده میکنید، از `async def` برای تعریف تابع خود استفاده کنید:
|
|
||||||
|
|
||||||
```Python hl_lines="9 14"
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from fastapi import FastAPI
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
async def read_root():
|
|
||||||
return {"Hello": "World"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
|
||||||
async def read_item(item_id: int, q: Optional[str] = None):
|
|
||||||
return {"item_id": item_id, "q": q}
|
|
||||||
```
|
|
||||||
|
|
||||||
**توجه**:
|
|
||||||
|
|
||||||
اگر با `async / await` آشنا نیستید، به بخش _"عجله دارید?"_ در صفحه درباره <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` و `await` در مستندات</a> مراجعه کنید.
|
|
||||||
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### اجرا کنید
|
|
||||||
|
|
||||||
با استفاده از دستور زیر سرور را اجرا کنید:
|
|
||||||
|
|
||||||
<div class="termy">
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ uvicorn main:app --reload
|
|
||||||
|
|
||||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
|
||||||
INFO: Started reloader process [28720]
|
|
||||||
INFO: Started server process [28722]
|
|
||||||
INFO: Waiting for application startup.
|
|
||||||
INFO: Application startup complete.
|
|
||||||
```
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<details markdown="1">
|
|
||||||
<summary>درباره دستور <code>uvicorn main:app --reload</code>...</summary>
|
|
||||||
|
|
||||||
دستور `uvicorn main:app` شامل موارد زیر است:
|
|
||||||
|
|
||||||
* `main`: فایل `main.py` (ماژول پایتون ایجاد شده).
|
|
||||||
* `app`: شیء ایجاد شده در فایل `main.py` در خط `app = FastAPI()`.
|
|
||||||
* `--reload`: ریستارت کردن سرور با تغییر کد. تنها در هنگام توسعه از این گزینه استفاده شود..
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### بررسی کنید
|
|
||||||
|
|
||||||
آدرس <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a> را در مرورگر خود باز کنید.
|
|
||||||
|
|
||||||
پاسخ JSON زیر را مشاهده خواهید کرد:
|
|
||||||
|
|
||||||
```JSON
|
|
||||||
{"item_id": 5, "q": "somequery"}
|
|
||||||
```
|
|
||||||
|
|
||||||
تا اینجا شما APIای ساختید که:
|
|
||||||
|
|
||||||
* درخواستهای HTTP به _مسیرهای_ `/` و `/items/{item_id}` را دریافت میکند.
|
|
||||||
* هردو _مسیر_ <abbr title="operations در OpenAPI">عملیات</abbr> (یا HTTP _متد_) `GET` را پشتیبانی میکند.
|
|
||||||
* _مسیر_ `/items/{item_id}` شامل <abbr title="Path Parameter">_پارامتر مسیر_</abbr> `item_id` از نوع `int` است.
|
|
||||||
* _مسیر_ `/items/{item_id}` شامل <abbr title="Query Parameter">_پارامتر پرسمان_</abbr> اختیاری `q` از نوع `str` است.
|
|
||||||
|
|
||||||
### مستندات API تعاملی
|
|
||||||
|
|
||||||
حال به آدرس <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> بروید.
|
|
||||||
|
|
||||||
مستندات API تعاملی (ایجاد شده به کمک <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) را مشاهده خواهید کرد:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### مستندات API جایگزین
|
|
||||||
|
|
||||||
حال به آدرس <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> بروید.
|
|
||||||
|
|
||||||
مستندات خودکار دیگری را مشاهده خواهید کرد که به کمک <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> ایجاد میشود:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## تغییر مثال
|
|
||||||
|
|
||||||
حال فایل `main.py` را مطابق زیر ویرایش کنید تا بتوانید <abbr title="Body">بدنه</abbr> یک درخواست `PUT` را دریافت کنید.
|
|
||||||
|
|
||||||
به کمک Pydantic بدنه درخواست را با <abbr title="Type">انواع</abbr> استاندارد پایتون تعریف کنید.
|
|
||||||
|
|
||||||
```Python hl_lines="4 9-12 25-27"
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
|
|
||||||
class Item(BaseModel):
|
|
||||||
name: str
|
|
||||||
price: float
|
|
||||||
is_offer: Union[bool, None] = None
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
def read_root():
|
|
||||||
return {"Hello": "World"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/items/{item_id}")
|
|
||||||
def read_item(item_id: int, q: Union[str, None] = None):
|
|
||||||
return {"item_id": item_id, "q": q}
|
|
||||||
|
|
||||||
|
|
||||||
@app.put("/items/{item_id}")
|
|
||||||
def update_item(item_id: int, item: Item):
|
|
||||||
return {"item_name": item.name, "item_id": item_id}
|
|
||||||
```
|
|
||||||
|
|
||||||
سرور به صورت خودکار ریاستارت میشود (زیرا پیشتر از گزینه `--reload` در دستور `uvicorn` استفاده کردیم).
|
|
||||||
|
|
||||||
### تغییر مستندات API تعاملی
|
|
||||||
|
|
||||||
مجددا به آدرس <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> بروید.
|
|
||||||
|
|
||||||
* مستندات API تعاملی به صورت خودکار بهروز شده است و شامل بدنه تعریف شده در مرحله قبل است:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* روی دکمه "Try it out" کلیک کنید، اکنون میتوانید پارامترهای مورد نیاز هر API را مشخص کرده و به صورت مستقیم با آنها تعامل کنید:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* سپس روی دکمه "Execute" کلیک کنید، خواهید دید که واسط کاربری با APIهای تعریف شده ارتباط برقرار کرده، پارامترهای مورد نیاز را به آنها ارسال میکند، سپس نتایج را دریافت کرده و در صفحه نشان میدهد:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### تغییر مستندات API جایگزین
|
|
||||||
|
|
||||||
حال به آدرس <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> بروید.
|
|
||||||
|
|
||||||
* خواهید دید که مستندات جایگزین نیز بهروزرسانی شده و شامل پارامتر پرسمان و بدنه تعریف شده میباشد:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### خلاصه
|
|
||||||
|
|
||||||
به طور خلاصه شما **یک بار** انواع پارامترها، بدنه و غیره را به عنوان پارامترهای ورودی تابع خود تعریف میکنید.
|
|
||||||
|
|
||||||
این کار را با استفاده از انواع استاندارد و مدرن موجود در پایتون انجام میدهید.
|
|
||||||
|
|
||||||
نیازی به یادگیری <abbr title="Syntax">نحو</abbr> جدید یا متدها و کلاسهای یک کتابخانه بخصوص و غیره نیست.
|
|
||||||
|
|
||||||
تنها **پایتون +۳.۶**.
|
|
||||||
|
|
||||||
به عنوان مثال برای یک پارامتر از نوع `int`:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
item_id: int
|
|
||||||
```
|
|
||||||
|
|
||||||
یا برای یک مدل پیچیدهتر مثل `Item`:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
item: Item
|
|
||||||
```
|
|
||||||
|
|
||||||
...و با همین اعلان تمامی قابلیتهای زیر در دسترس قرار میگیرد:
|
|
||||||
|
|
||||||
* پشتیبانی ویرایشگر متنی شامل:
|
|
||||||
* تکمیل کد.
|
|
||||||
* بررسی انواع داده.
|
|
||||||
* اعتبارسنجی داده:
|
|
||||||
* خطاهای خودکار و مشخص در هنگام نامعتبر بودن داده.
|
|
||||||
* اعتبارسنجی، حتی برای اشیاء JSON تو در تو.
|
|
||||||
* <abbr title="serialization, parsing, marshalling">تبدیل</abbr> داده ورودی: که از شبکه رسیده به انواع و داده پایتونی. این داده شامل:
|
|
||||||
* JSON.
|
|
||||||
* <abbr title="Path parameters">پارامترهای مسیر</abbr>.
|
|
||||||
* <abbr title="Query parameters">پارامترهای پرسمان</abbr>.
|
|
||||||
* <abbr title="Cookies">کوکیها</abbr>.
|
|
||||||
* <abbr title="Headers">سرآیندها (هدرها)</abbr>.
|
|
||||||
* <abbr title="Forms">فرمها</abbr>.
|
|
||||||
* <abbr title="Files">فایلها</abbr>.
|
|
||||||
* <abbr title="serialization, parsing, marshalling">تبدیل</abbr> داده خروجی: تبدیل از انواع و داده پایتون به داده شبکه (مانند JSON):
|
|
||||||
* تبدیل انواع داده پایتونی (`str`, `int`, `float`, `bool`, `list` و غیره).
|
|
||||||
* اشیاء `datetime`.
|
|
||||||
* اشیاء `UUID`.
|
|
||||||
* qمدلهای پایگاهداده.
|
|
||||||
* و موارد بیشمار دیگر.
|
|
||||||
* دو مدل مستند API تعاملی خودکار :
|
|
||||||
* Swagger UI.
|
|
||||||
* ReDoc.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
به مثال قبلی باز میگردیم، در این مثال **FastAPI** موارد زیر را انجام میدهد:
|
|
||||||
|
|
||||||
* اعتبارسنجی اینکه پارامتر `item_id` در مسیر درخواستهای `GET` و `PUT` موجود است.
|
|
||||||
* اعتبارسنجی اینکه پارامتر `item_id` در درخواستهای `GET` و `PUT` از نوع `int` است.
|
|
||||||
* اگر غیر از این موارد باشد، سرویسگیرنده خطای مفید و مشخصی دریافت خواهد کرد.
|
|
||||||
* بررسی وجود پارامتر پرسمان اختیاری `q` (مانند `http://127.0.0.1:8000/items/foo?q=somequery`) در درخواستهای `GET`.
|
|
||||||
* از آنجا که پارامتر `q` با `= None` مقداردهی شده است، این پارامتر اختیاری است.
|
|
||||||
* اگر از مقدار اولیه `None` استفاده نکنیم، این پارامتر الزامی خواهد بود (همانند بدنه درخواست در درخواست `PUT`).
|
|
||||||
* برای درخواستهای `PUT` به آدرس `/items/{item_id}`، بدنه درخواست باید از نوع JSON تعریف شده باشد:
|
|
||||||
* بررسی اینکه بدنه شامل فیلدی با نام `name` و از نوع `str` است.
|
|
||||||
* بررسی اینکه بدنه شامل فیلدی با نام `price` و از نوع `float` است.
|
|
||||||
* بررسی اینکه بدنه شامل فیلدی اختیاری با نام `is_offer` است، که در صورت وجود باید از نوع `bool` باشد.
|
|
||||||
* تمامی این موارد برای اشیاء JSON در هر عمقی قابل بررسی میباشد.
|
|
||||||
* تبدیل از/به JSON به صورت خودکار.
|
|
||||||
* مستندسازی همه چیز با استفاده از OpenAPI، که میتوان از آن برای موارد زیر استفاده کرد:
|
|
||||||
* سیستم مستندات تعاملی.
|
|
||||||
* تولید خودکار کد سرویسگیرنده در زبانهای برنامهنویسی بیشمار.
|
|
||||||
* فراهم سازی ۲ مستند تعاملی مبتنی بر وب به صورت پیشفرض.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
موارد ذکر شده تنها پارهای از ویژگیهای بیشمار FastAPI است اما ایدهای کلی از طرز کار آن در اختیار قرار میدهد.
|
|
||||||
|
|
||||||
خط زیر را به این صورت تغییر دهید:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
return {"item_name": item.name, "item_id": item_id}
|
|
||||||
```
|
|
||||||
|
|
||||||
از:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
... "item_name": item.name ...
|
|
||||||
```
|
|
||||||
|
|
||||||
به:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
... "item_price": item.price ...
|
|
||||||
```
|
|
||||||
|
|
||||||
در حین تایپ کردن توجه کنید که چگونه ویرایشگر، ویژگیهای کلاس `Item` را تشخیص داده و به تکمیل خودکار آنها کمک میکند:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
برای مشاهده مثالهای کاملتر که شامل قابلیتهای بیشتری از FastAPI باشد به بخش <a href="https://fastapi.tiangolo.com/tutorial/">آموزش - راهنمای کاربر</a> مراجعه کنید.
|
|
||||||
|
|
||||||
**هشدار اسپویل**: بخش آموزش - راهنمای کاربر شامل موارد زیر است:
|
|
||||||
|
|
||||||
* اعلان **پارامترهای** موجود در بخشهای دیگر درخواست، شامل: **سرآیند (هدر)ها**، **کوکیها**، **فیلدهای فرم** و **فایلها**.
|
|
||||||
* چگونگی تنظیم **<abbr title="Validation Constraints">محدودیتهای اعتبارسنجی</abbr>** به عنوان مثال `maximum_length` یا `regex`.
|
|
||||||
* سیستم **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** قوی و کاربردی.
|
|
||||||
* امنیت و تایید هویت, شامل پشتیبانی از **OAuth2** مبتنی بر **JWT tokens** و **HTTP Basic**.
|
|
||||||
* تکنیک پیشرفته برای تعریف **مدلهای چند سطحی JSON** (بر اساس Pydantic).
|
|
||||||
* قابلیتهای اضافی دیگر (بر اساس Starlette) شامل:
|
|
||||||
* **<abbr title="WebSocket">وبسوکت</abbr>**
|
|
||||||
* **GraphQL**
|
|
||||||
* تستهای خودکار آسان مبتنی بر HTTPX و `pytest`
|
|
||||||
* **CORS**
|
|
||||||
* **Cookie Sessions**
|
|
||||||
* و موارد بیشمار دیگر.
|
|
||||||
|
|
||||||
## کارایی
|
|
||||||
|
|
||||||
معیار (بنچمارک)های مستقل TechEmpower حاکی از آن است که برنامههای **FastAPI** که تحت Uvicorn اجرا میشود، <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">یکی از سریعترین فریمورکهای مبتنی بر پایتون</a>، است که کمی ضعیفتر از Starlette و Uvicorn عمل میکند (فریمورک و سروری که FastAPI بر اساس آنها ایجاد شده است) (*)
|
|
||||||
|
|
||||||
برای درک بهتری از این موضوع به بخش <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">بنچمارکها</a> مراجعه کنید.
|
|
||||||
|
|
||||||
## نیازمندیهای اختیاری
|
|
||||||
|
|
||||||
استفاده شده توسط Pydantic:
|
|
||||||
|
|
||||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - برای اعتبارسنجی آدرسهای ایمیل.
|
|
||||||
|
|
||||||
استفاده شده توسط Starlette:
|
|
||||||
|
|
||||||
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - در صورتی که میخواهید از `TestClient` استفاده کنید.
|
|
||||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - در صورتی که میخواهید از `FileResponse` و `StaticFiles` استفاده کنید.
|
|
||||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - در صورتی که بخواهید از پیکربندی پیشفرض برای قالبها استفاده کنید.
|
|
||||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - در صورتی که بخواهید با استفاده از `request.form()` از قابلیت <abbr title="تبدیل رشته متنی موجود در درخواست HTTP به انواع داده پایتون">"تجزیه (parse)"</abbr> فرم استفاده کنید.
|
|
||||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - در صورتی که بخواید از `SessionMiddleware` پشتیبانی کنید.
|
|
||||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - برای پشتیبانی `SchemaGenerator` در Starlet (به احتمال زیاد برای کار کردن با FastAPI به آن نیازی پیدا نمیکنید).
|
|
||||||
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - در صورتی که از `GraphQLApp` پشتیبانی میکنید.
|
|
||||||
|
|
||||||
استفاده شده توسط FastAPI / Starlette:
|
|
||||||
|
|
||||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - برای سرور اجرا کننده برنامه وب.
|
|
||||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - در صورتی که بخواهید از `ORJSONResponse` استفاده کنید.
|
|
||||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - در صورتی که بخواهید از `UJSONResponse` استفاده کنید.
|
|
||||||
|
|
||||||
میتوان همه این موارد را با استفاده از دستور `pip install fastapi[all]`. به صورت یکجا نصب کرد.
|
|
||||||
|
|
||||||
## لایسنس
|
|
||||||
|
|
||||||
این پروژه مشمول قوانین و مقررات لایسنس MIT است.
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# یادگیری
|
|
||||||
|
|
||||||
اینجا بخشهای مقدماتی و آموزشهایی هستن که برای یادگیری **FastAPI** بهت کمک میکنن.
|
|
||||||
|
|
||||||
میتونی اینو یه **کتاب**، یه **دوره آموزشی**، یا راه **رسمی** و پیشنهادی برای یادگیری FastAPI در نظر بگیری. 😎
|
|
||||||
|
|
@ -1,578 +0,0 @@
|
||||||
# مقدمهای بر انواع نوع در پایتون
|
|
||||||
|
|
||||||
پایتون از "نوعنما"های اختیاری (که بهشون "type hints" یا "type annotations" هم میگن) پشتیبانی میکنه.
|
|
||||||
|
|
||||||
این **"نوعنماها"** یا annotationها یه سینتکس خاص هستن که بهت اجازه میدن <abbr title="مثلاً: str, int, float, bool">نوع</abbr> یه متغیر رو مشخص کنی.
|
|
||||||
|
|
||||||
با مشخص کردن نوع متغیرها، ویرایشگرها و ابزارها میتونن پشتیبانی بهتری بهت بدن.
|
|
||||||
|
|
||||||
این فقط یه **آموزش سریع / یادآوری** در مورد نوعنماهای پایتونه. فقط حداقل چیزایی که برای استفاده ازشون با **FastAPI** لازمه رو پوشش میده... که در واقع خیلی کمه.
|
|
||||||
|
|
||||||
**FastAPI** کاملاً بر پایه این نوعنماهاست و این بهش کلی مزیت و فایده میده.
|
|
||||||
|
|
||||||
ولی حتی اگه هیچوقت از **FastAPI** استفاده نکنی، بازم یادگیری یه کم در موردشون به نفعته.
|
|
||||||
|
|
||||||
/// note
|
|
||||||
|
|
||||||
اگه حرفهای پایتونی و همهچیز رو در مورد نوعنماها میدونی، برو سراغ فصل بعدی.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## انگیزه
|
|
||||||
|
|
||||||
بیاید با یه مثال ساده شروع کنیم:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial001.py *}
|
|
||||||
|
|
||||||
وقتی این برنامه رو اجرا کنی، خروجی اینه:
|
|
||||||
|
|
||||||
```
|
|
||||||
John Doe
|
|
||||||
```
|
|
||||||
|
|
||||||
این تابع این کارا رو میکنه:
|
|
||||||
|
|
||||||
* یه `first_name` و `last_name` میگیره.
|
|
||||||
* حرف اول هر کدوم رو با `title()` بزرگ میکنه.
|
|
||||||
* <abbr title="اونا رو کنار هم میذاره، یکی بعد از اون یکی.">ترکیبشون</abbr> میکنه با یه فاصله وسطشون.
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
|
|
||||||
|
|
||||||
### ویرایشش کن
|
|
||||||
|
|
||||||
این یه برنامه خیلی سادهست.
|
|
||||||
|
|
||||||
ولی حالا تصور کن داری از صفر مینویسیش.
|
|
||||||
|
|
||||||
یه جایی شروع کردی به تعریف تابع، پارامترهات آمادهست...
|
|
||||||
|
|
||||||
ولی بعد باید "اون متدی که حرف اول رو بزرگ میکنه" رو صدا کنی.
|
|
||||||
|
|
||||||
آیا اسمش `upper` بود؟ یا `uppercase`؟ شاید `first_uppercase`؟ یا `capitalize`؟
|
|
||||||
|
|
||||||
بعد، با دوست قدیمی برنامهنویسا، تکمیل خودکار ویرایشگر، امتحان میکنی.
|
|
||||||
|
|
||||||
پارامتر اول تابع، `first_name` رو تایپ میکنی، بعد یه نقطه (`.`) میذاری و `Ctrl+Space` رو میزنی تا تکمیل خودکار بیاد.
|
|
||||||
|
|
||||||
ولی متأسفانه، چیز مفیدی نمیگیری:
|
|
||||||
|
|
||||||
<img src="/img/python-types/image01.png">
|
|
||||||
|
|
||||||
### نوع اضافه کن
|
|
||||||
|
|
||||||
بیا فقط یه خط از نسخه قبلی رو تغییر بدیم.
|
|
||||||
|
|
||||||
دقیقاً این بخش، پارامترهای تابع رو، از:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
first_name, last_name
|
|
||||||
```
|
|
||||||
|
|
||||||
به:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
first_name: str, last_name: str
|
|
||||||
```
|
|
||||||
|
|
||||||
عوض میکنیم.
|
|
||||||
|
|
||||||
همینه.
|
|
||||||
|
|
||||||
اینا همون "نوعنماها" هستن:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
|
|
||||||
|
|
||||||
این با تعریف مقدار پیشفرض فرق داره، مثل:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
first_name="john", last_name="doe"
|
|
||||||
```
|
|
||||||
|
|
||||||
یه چیز متفاوته.
|
|
||||||
|
|
||||||
ما از دونقطه (`:`) استفاده میکنیم، نه علامت مساوی (`=`).
|
|
||||||
|
|
||||||
و اضافه کردن نوعنماها معمولاً چیزی که اتفاق میافته رو از چیزی که بدون اونا میافتاد تغییر نمیده.
|
|
||||||
|
|
||||||
ولی حالا، دوباره تصور کن وسط ساختن اون تابع هستی، ولی این بار با نوعنماها.
|
|
||||||
|
|
||||||
توی همون نقطه، سعی میکنی تکمیل خودکار رو با `Ctrl+Space` فعال کنی و اینو میبینی:
|
|
||||||
|
|
||||||
<img src="/img/python-types/image02.png">
|
|
||||||
|
|
||||||
با این، میتونی اسکرول کنی، گزینهها رو ببینی، تا وقتی که اون چیزی که "به نظرت آشنا میاد" رو پیدا کنی:
|
|
||||||
|
|
||||||
<img src="/img/python-types/image03.png">
|
|
||||||
|
|
||||||
## انگیزه بیشتر
|
|
||||||
|
|
||||||
این تابع رو چک کن، الان نوعنما داره:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
|
|
||||||
|
|
||||||
چون ویرایشگر نوع متغیرها رو میدونه، فقط تکمیل خودکار نمیگیری، بلکه چک خطاها هم داری:
|
|
||||||
|
|
||||||
<img src="/img/python-types/image04.png">
|
|
||||||
|
|
||||||
حالا میدونی که باید درستش کنی، `age` رو با `str(age)` به یه رشته تبدیل کنی:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
|
|
||||||
|
|
||||||
## تعریف نوعها
|
|
||||||
|
|
||||||
تازه اصلیترین جا برای تعریف نوعنماها رو دیدی. بهعنوان پارامترهای تابع.
|
|
||||||
|
|
||||||
این هم اصلیترین جاییه که با **FastAPI** ازشون استفاده میکنی.
|
|
||||||
|
|
||||||
### نوعهای ساده
|
|
||||||
|
|
||||||
میتونی همه نوعهای استاندارد پایتون رو تعریف کنی، نه فقط `str`.
|
|
||||||
|
|
||||||
مثلاً میتونی از اینا استفاده کنی:
|
|
||||||
|
|
||||||
* `int`
|
|
||||||
* `float`
|
|
||||||
* `bool`
|
|
||||||
* `bytes`
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
|
|
||||||
|
|
||||||
### نوعهای عمومی با پارامترهای نوع
|
|
||||||
|
|
||||||
یه سری ساختار داده هستن که میتونن مقدارهای دیگه رو نگه دارن، مثل `dict`، `list`، `set` و `tuple`. و مقدارهای داخلیشون هم میتونن نوع خودشون رو داشته باشن.
|
|
||||||
|
|
||||||
به این نوعها که نوعهای داخلی دارن میگن "**عمومی**" یا "generic". و میشه اونا رو تعریف کرد، حتی با نوعهای داخلیشون.
|
|
||||||
|
|
||||||
برای تعریف این نوعها و نوعهای داخلیشون، میتونی از ماژول استاندارد پایتون `typing` استفاده کنی. این ماژول مخصوص پشتیبانی از نوعنماهاست.
|
|
||||||
|
|
||||||
#### نسخههای جدیدتر پایتون
|
|
||||||
|
|
||||||
سینتکس با استفاده از `typing` با همه نسخهها، از پایتون 3.6 تا جدیدترینها، از جمله پایتون 3.9، 3.10 و غیره **سازگاره**.
|
|
||||||
|
|
||||||
با پیشرفت پایتون، **نسخههای جدیدتر** پشتیبانی بهتری برای این نوعنماها دارن و توی خیلی موارد حتی لازم نیست ماژول `typing` رو وارد کنی و ازش برای تعریف نوعنماها استفاده کنی.
|
|
||||||
|
|
||||||
اگه بتونی برای پروژهات از یه نسخه جدیدتر پایتون استفاده کنی، میتونی از این سادگی اضافه بهره ببری.
|
|
||||||
|
|
||||||
توی همه مستندات، مثالهایی هستن که با هر نسخه پایتون سازگارن (وقتی تفاوتی هست).
|
|
||||||
|
|
||||||
مثلاً "**Python 3.6+**" یعنی با پایتون 3.6 یا بالاتر (مثل 3.7، 3.8، 3.9، 3.10 و غیره) سازگاره. و "**Python 3.9+**" یعنی با پایتون 3.9 یا بالاتر (مثل 3.10 و غیره) سازگاره.
|
|
||||||
|
|
||||||
اگه بتونی از **جدیدترین نسخههای پایتون** استفاده کنی، از مثالهای نسخه آخر استفاده کن، چون اونا **بهترین و سادهترین سینتکس** رو دارن، مثلاً "**Python 3.10+**".
|
|
||||||
|
|
||||||
#### لیست
|
|
||||||
|
|
||||||
مثلاً، بیایم یه متغیر تعریف کنیم که یه `list` از `str` باشه.
|
|
||||||
|
|
||||||
//// tab | Python 3.9+
|
|
||||||
|
|
||||||
متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن.
|
|
||||||
|
|
||||||
بهعنوان نوع، `list` رو بذار.
|
|
||||||
|
|
||||||
چون لیست یه نوعه که نوعهای داخلی داره، اونا رو توی کروشهها میذاری:
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
{!> ../../docs_src/python_types/tutorial006_py39.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
از `typing`، `List` رو (با `L` بزرگ) وارد کن:
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
{!> ../../docs_src/python_types/tutorial006.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن.
|
|
||||||
|
|
||||||
بهعنوان نوع، `List` رو که از `typing` وارد کردی بذار.
|
|
||||||
|
|
||||||
چون لیست یه نوعه که نوعهای داخلی داره، اونا رو توی کروشهها میذاری:
|
|
||||||
|
|
||||||
```Python hl_lines="4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial006.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
/// info
|
|
||||||
|
|
||||||
اون نوعهای داخلی توی کروشهها بهشون "پارامترهای نوع" میگن.
|
|
||||||
|
|
||||||
توی این مورد، `str` پارامتر نوعیه که به `List` (یا `list` توی پایتون 3.9 و بالاتر) پاس داده شده.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
یعنی: "متغیر `items` یه `list` هست، و هر کدوم از آیتمهای این لیست یه `str` هستن".
|
|
||||||
|
|
||||||
/// tip
|
|
||||||
|
|
||||||
اگه از پایتون 3.9 یا بالاتر استفاده میکنی، لازم نیست `List` رو از `typing` وارد کنی، میتونی همون نوع معمولی `list` رو به جاش استفاده کنی.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
با این کار، ویرایشگرت حتی وقتی داری آیتمهای لیست رو پردازش میکنی بهت کمک میکنه:
|
|
||||||
|
|
||||||
<img src="/img/python-types/image05.png">
|
|
||||||
|
|
||||||
بدون نوعها، رسیدن به این تقریباً غیرممکنه.
|
|
||||||
|
|
||||||
توجه کن که متغیر `item` یکی از عناصر توی لیست `items` هست.
|
|
||||||
|
|
||||||
و با این حال، ویرایشگر میدونه که یه `str` هست و براش پشتیبانی میده.
|
|
||||||
|
|
||||||
#### تاپل و ست
|
|
||||||
|
|
||||||
برای تعریف `tuple`ها و `set`ها هم همین کار رو میکنی:
|
|
||||||
|
|
||||||
//// tab | Python 3.9+
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
{!> ../../docs_src/python_types/tutorial007_py39.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial007.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
یعنی:
|
|
||||||
|
|
||||||
* متغیر `items_t` یه `tuple` با 3 تا آیتمه، یه `int`، یه `int` دیگه، و یه `str`.
|
|
||||||
* متغیر `items_s` یه `set` هست، و هر کدوم از آیتمهاش از نوع `bytes` هستن.
|
|
||||||
|
|
||||||
#### دیکشنری
|
|
||||||
|
|
||||||
برای تعریف یه `dict`، 2 تا پارامتر نوع میدی، که با کاما از هم جدا شدن.
|
|
||||||
|
|
||||||
پارامتر نوع اول برای کلیدهای `dict` هست.
|
|
||||||
|
|
||||||
پارامتر نوع دوم برای مقدارهای `dict` هست:
|
|
||||||
|
|
||||||
//// tab | Python 3.9+
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
{!> ../../docs_src/python_types/tutorial008_py39.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial008.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
یعنی:
|
|
||||||
|
|
||||||
* متغیر `prices` یه `dict` هست:
|
|
||||||
* کلیدهای این `dict` از نوع `str` هستن (مثلاً اسم هر آیتم).
|
|
||||||
* مقدارهای این `dict` از نوع `float` هستن (مثلاً قیمت هر آیتم).
|
|
||||||
|
|
||||||
#### اتحادیه
|
|
||||||
|
|
||||||
میتونی تعریف کنی که یه متغیر میتونه هر کدوم از **چند تا نوع** باشه، مثلاً یه `int` یا یه `str`.
|
|
||||||
|
|
||||||
توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) میتونی از نوع `Union` توی `typing` استفاده کنی و نوعهای ممکن رو توی کروشهها بذاری.
|
|
||||||
|
|
||||||
توی پایتون 3.10 یه **سینتکس جدید** هم هست که میتونی نوعهای ممکن رو با یه <abbr title="بهش 'عملگر بیتی یا' هم میگن، ولی اینجا معنیش مهم نیست">خط عمودی (`|`)</abbr> جدا کنی.
|
|
||||||
|
|
||||||
//// tab | Python 3.10+
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial008b.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
توی هر دو حالت یعنی `item` میتونه یه `int` یا یه `str` باشه.
|
|
||||||
|
|
||||||
#### شاید `None`
|
|
||||||
|
|
||||||
میتونی تعریف کنی که یه مقدار میتونه یه نوع باشه، مثلاً `str`، ولی میتونه `None` هم باشه.
|
|
||||||
|
|
||||||
توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) میتونی با وارد کردن و استفاده از `Optional` از ماژول `typing` اینو تعریف کنی.
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!../../docs_src/python_types/tutorial009.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
استفاده از `Optional[str]` به جای فقط `str` به ویرایشگر کمک میکنه خطاهایی که ممکنه فکر کنی یه مقدار همیشه `str` هست رو پیدا کنه، در حالی که میتونه `None` هم باشه.
|
|
||||||
|
|
||||||
`Optional[Something]` در واقع میانبر برای `Union[Something, None]` هست، این دو تا معادلن.
|
|
||||||
|
|
||||||
یعنی توی پایتون 3.10، میتونی از `Something | None` استفاده کنی:
|
|
||||||
|
|
||||||
//// tab | Python 3.10+
|
|
||||||
|
|
||||||
```Python hl_lines="1"
|
|
||||||
{!> ../../docs_src/python_types/tutorial009_py310.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial009.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+ جایگزین
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial009b.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
#### استفاده از `Union` یا `Optional`
|
|
||||||
|
|
||||||
اگه از نسخه پایتون زیر 3.10 استفاده میکنی، یه نکته از دید خیلی **شخصی** خودم:
|
|
||||||
|
|
||||||
* 🚨 از `Optional[SomeType]` استفاده نکن
|
|
||||||
* به جاش ✨ **از `Union[SomeType, None]` استفاده کن** ✨.
|
|
||||||
|
|
||||||
هر دو معادلن و زیر پوسته یکیان، ولی من `Union` رو به `Optional` ترجیح میدم چون کلمه "**اختیاری**" انگار暗示 میکنه که مقدار اختیاریه، در حالی که در واقع یعنی "میتونه `None` باشه"، حتی اگه اختیاری نباشه و هنوز لازم باشه.
|
|
||||||
|
|
||||||
فکر میکنم `Union[SomeType, None]` واضحتر نشون میده چی معنی میده.
|
|
||||||
|
|
||||||
فقط بحث کلمات و اسمهاست. ولی این کلمات میتونن رو طرز فکر تو و تیمت نسبت به کد تأثیر بذارن.
|
|
||||||
|
|
||||||
بهعنوان مثال، این تابع رو ببین:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *}
|
|
||||||
|
|
||||||
پارامتر `name` بهعنوان `Optional[str]` تعریف شده، ولی **اختیاری نیست**، نمیتونی تابع رو بدون پارامتر صدا کنی:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
say_hi() # اوه نه، این خطا میده! 😱
|
|
||||||
```
|
|
||||||
|
|
||||||
پارامتر `name` **هنوز لازمه** (نه *اختیاری*) چون مقدار پیشفرض نداره. با این حال، `name` مقدار `None` رو قبول میکنه:
|
|
||||||
|
|
||||||
```Python
|
|
||||||
say_hi(name=None) # این کار میکنه، None معتبره 🎉
|
|
||||||
```
|
|
||||||
|
|
||||||
خبر خوب اینه که وقتی رو پایتون 3.10 باشی، لازم نیست نگران این باشی، چون میتونی بهسادگی از `|` برای تعریف اتحادیه نوعها استفاده کنی:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
|
|
||||||
|
|
||||||
اون موقع دیگه لازم نیست نگران اسمهایی مثل `Optional` و `Union` باشی. 😎
|
|
||||||
|
|
||||||
#### نوعهای عمومی
|
|
||||||
|
|
||||||
این نوعهایی که پارامترهای نوع رو توی کروشهها میگیرن بهشون **نوعهای عمومی** یا **Generics** میگن، مثلاً:
|
|
||||||
|
|
||||||
//// tab | Python 3.10+
|
|
||||||
|
|
||||||
میتونی از همون نوعهای داخلی بهعنوان نوعهای عمومی استفاده کنی (با کروشهها و نوعها داخلشون):
|
|
||||||
|
|
||||||
* `list`
|
|
||||||
* `tuple`
|
|
||||||
* `set`
|
|
||||||
* `dict`
|
|
||||||
|
|
||||||
و همونطور که توی پایتون 3.8 بود، از ماژول `typing`:
|
|
||||||
|
|
||||||
* `Union`
|
|
||||||
* `Optional` (همونطور که توی پایتون 3.8 بود)
|
|
||||||
* ...و بقیه.
|
|
||||||
|
|
||||||
توی پایتون 3.10، بهعنوان جایگزین برای استفاده از نوعهای عمومی `Union` و `Optional`، میتونی از <abbr title="بهش 'عملگر بیتی یا' هم میگن، ولی اینجا معنیش مهم نیست">خط عمودی (`|`)</abbr> برای تعریف اتحادیه نوعها استفاده کنی، که خیلی بهتر و سادهتره.
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.9+
|
|
||||||
|
|
||||||
میتونی از همون نوعهای داخلی بهعنوان نوعهای عمومی استفاده کنی (با کروشهها و نوعها داخلشون):
|
|
||||||
|
|
||||||
* `list`
|
|
||||||
* `tuple`
|
|
||||||
* `set`
|
|
||||||
* `dict`
|
|
||||||
|
|
||||||
و همونطور که توی پایتون 3.8 بود، از ماژول `typing`:
|
|
||||||
|
|
||||||
* `Union`
|
|
||||||
* `Optional`
|
|
||||||
* ...و بقیه.
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
* `List`
|
|
||||||
* `Tuple`
|
|
||||||
* `Set`
|
|
||||||
* `Dict`
|
|
||||||
* `Union`
|
|
||||||
* `Optional`
|
|
||||||
* ...و بقیه.
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
### کلاسها بهعنوان نوع
|
|
||||||
|
|
||||||
میتونی یه کلاس رو هم بهعنوان نوع یه متغیر تعریف کنی.
|
|
||||||
|
|
||||||
فرض کن یه کلاس `Person` داری، با یه نام:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
|
|
||||||
|
|
||||||
بعد میتونی یه متغیر رو از نوع `Person` تعریف کنی:
|
|
||||||
|
|
||||||
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
|
|
||||||
|
|
||||||
و بعد، دوباره، همه پشتیبانی ویرایشگر رو داری:
|
|
||||||
|
|
||||||
<img src="/img/python-types/image06.png">
|
|
||||||
|
|
||||||
توجه کن که این یعنی "`one_person` یه **نمونه** از کلاس `Person` هست".
|
|
||||||
|
|
||||||
یعنی "`one_person` خود **کلاس** به اسم `Person` نیست".
|
|
||||||
|
|
||||||
## مدلهای Pydantic
|
|
||||||
|
|
||||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> یه کتابخونه پایتونه برای اعتبارسنجی دادهها.
|
|
||||||
|
|
||||||
"شکل" دادهها رو بهعنوان کلاسهایی با ویژگیها تعریف میکنی.
|
|
||||||
|
|
||||||
و هر ویژگی یه نوع داره.
|
|
||||||
|
|
||||||
بعد یه نمونه از اون کلاس رو با یه سری مقدار میسازی و اون مقدارها رو اعتبارسنجی میکنه، به نوع مناسب تبدیلشون میکنه (اگه لازم باشه) و یه شیء با همه دادهها بهت میده.
|
|
||||||
|
|
||||||
و با اون شیء نهایی همه پشتیبانی ویرایشگر رو میگیری.
|
|
||||||
|
|
||||||
یه مثال از مستندات رسمی Pydantic:
|
|
||||||
|
|
||||||
//// tab | Python 3.10+
|
|
||||||
|
|
||||||
```Python
|
|
||||||
{!> ../../docs_src/python_types/tutorial011_py310.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.9+
|
|
||||||
|
|
||||||
```Python
|
|
||||||
{!> ../../docs_src/python_types/tutorial011_py39.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
```Python
|
|
||||||
{!> ../../docs_src/python_types/tutorial011.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
/// info
|
|
||||||
|
|
||||||
برای اطلاعات بیشتر در مورد <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic، مستنداتش رو چک کن</a>.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
**FastAPI** کاملاً بر پایه Pydantic هست.
|
|
||||||
|
|
||||||
توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} خیلی بیشتر از اینا رو توی عمل میبینی.
|
|
||||||
|
|
||||||
/// tip
|
|
||||||
|
|
||||||
Pydantic یه رفتار خاص داره وقتی از `Optional` یا `Union[Something, None]` بدون مقدار پیشفرض استفاده میکنی، میتونی توی مستندات Pydantic در مورد <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">فیلدهای اختیاری لازم</a> بیشتر بخونی.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## نوعنماها با Annotationهای متادیتا
|
|
||||||
|
|
||||||
پایتون یه قابلیت هم داره که بهت اجازه میده **<abbr title="داده در مورد داده، اینجا یعنی اطلاعات در مورد نوع، مثلاً یه توضیح">متادیتا</abbr> اضافی** رو توی این نوعنماها بذاری با استفاده از `Annotated`.
|
|
||||||
|
|
||||||
//// tab | Python 3.9+
|
|
||||||
|
|
||||||
توی پایتون 3.9، `Annotated` بخشی از کتابخونه استاندارده، پس میتونی از `typing` واردش کنی.
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial013_py39.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
//// tab | Python 3.8+
|
|
||||||
|
|
||||||
توی نسخههای زیر پایتون 3.9، `Annotated` رو از `typing_extensions` وارد میکنی.
|
|
||||||
|
|
||||||
با **FastAPI** از قبل نصب شده.
|
|
||||||
|
|
||||||
```Python hl_lines="1 4"
|
|
||||||
{!> ../../docs_src/python_types/tutorial013.py!}
|
|
||||||
```
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
خود پایتون با این `Annotated` کاری نمیکنه. و برای ویرایشگرها و ابزارهای دیگه، نوع هنوز `str` هست.
|
|
||||||
|
|
||||||
ولی میتونی از این فضا توی `Annotated` استفاده کنی تا به **FastAPI** متادیتای اضافی در مورد اینکه چطور میخوای برنامهات رفتار کنه بدی.
|
|
||||||
|
|
||||||
نکته مهم اینه که **اولین *پارامتر نوع*** که به `Annotated` میدی، **نوع واقعی** هست. بقیش فقط متادیتا برای ابزارهای دیگهست.
|
|
||||||
|
|
||||||
الان فقط باید بدونی که `Annotated` وجود داره، و اینکه پایتون استاندارده. 😎
|
|
||||||
|
|
||||||
بعداً میبینی که چقدر **قوی** میتونه باشه.
|
|
||||||
|
|
||||||
/// tip
|
|
||||||
|
|
||||||
اینکه این **پایتون استاندارده** یعنی هنوز **بهترین تجربه توسعهدهنده** رو توی ویرایشگرت، با ابزارهایی که برای تحلیل و بازسازی کدت استفاده میکنی و غیره میگیری. ✨
|
|
||||||
|
|
||||||
و همینطور کدت با خیلی از ابزارها و کتابخونههای دیگه پایتون خیلی سازگار میمونه. 🚀
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## نوعنماها توی **FastAPI**
|
|
||||||
|
|
||||||
**FastAPI** از این نوعنماها استفاده میکنه تا چند تا کار بکنه.
|
|
||||||
|
|
||||||
با **FastAPI** پارامترها رو با نوعنماها تعریف میکنی و اینا رو میگیری:
|
|
||||||
|
|
||||||
* **پشتیبانی ویرایشگر**.
|
|
||||||
* **چک نوعها**.
|
|
||||||
|
|
||||||
...و **FastAPI** از همون تعریفها برای اینا استفاده میکنه:
|
|
||||||
|
|
||||||
* **تعریف نیازها**: از پارامترهای مسیر درخواست، پارامترهای کوئری، هدرها، بدنهها، وابستگیها و غیره.
|
|
||||||
* **تبدیل داده**: از درخواست به نوع مورد نیاز.
|
|
||||||
* **اعتبارسنجی داده**: که از هر درخواست میاد:
|
|
||||||
* تولید **خطاهای خودکار** که به کلاینت برمیگرده وقتی داده نامعتبره.
|
|
||||||
* **مستندسازی** API با استفاده از OpenAPI:
|
|
||||||
* که بعدش توسط رابطهای کاربری مستندات تعاملی خودکار استفاده میشه.
|
|
||||||
|
|
||||||
اینا شاید همهش انتزاعی به نظر بیاد. نگران نباش. همه اینا رو توی عمل توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} میبینی.
|
|
||||||
|
|
||||||
نکته مهم اینه که با استفاده از نوعهای استاندارد پایتون، توی یه جا (به جای اضافه کردن کلاسهای بیشتر، دکوراتورها و غیره)، **FastAPI** کلی از کار رو برات انجام میده.
|
|
||||||
|
|
||||||
/// info
|
|
||||||
|
|
||||||
اگه همه آموزش رو گذروندی و برگشتی که بیشتر در مورد نوعها ببینی، یه منبع خوب <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">"تقلبنامه" از `mypy`</a> هست.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
# میانافزار - middleware
|
|
||||||
|
|
||||||
شما میتوانید میانافزارها را در **FastAPI** اضافه کنید.
|
|
||||||
|
|
||||||
"میانافزار" یک تابع است که با هر درخواست(request) قبل از پردازش توسط هر path operation (عملیات مسیر) خاص کار میکند. همچنین با هر پاسخ(response) قبل از بازگشت آن نیز کار میکند.
|
|
||||||
|
|
||||||
* هر **درخواستی (request)** که به برنامه شما می آید را می گیرد.
|
|
||||||
* سپس می تواند کاری برای آن **درخواست** انجام دهید یا هر کد مورد نیازتان را اجرا کنید.
|
|
||||||
* سپس **درخواست** را به بخش دیگری از برنامه (توسط یک path operation مشخص) برای پردازش ارسال می کند.
|
|
||||||
* سپس **پاسخ** تولید شده توسط برنامه را (توسط یک path operation مشخص) دریافت میکند.
|
|
||||||
* می تواند کاری با **پاسخ** انجام دهید یا هر کد مورد نیازتان را اجرا کند.
|
|
||||||
* سپس **پاسخ** را برمی گرداند.
|
|
||||||
|
|
||||||
/// توجه | جزئیات فنی
|
|
||||||
|
|
||||||
در صورت وجود وابستگی هایی با `yield`، کد خروجی **پس از** اجرای میانافزار اجرا خواهد شد.
|
|
||||||
|
|
||||||
در صورت وجود هر گونه وظایف پس زمینه (که در ادامه توضیح داده میشوند)، تمام میانافزارها *پس از آن* اجرا خواهند شد.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## ساخت یک میان افزار
|
|
||||||
|
|
||||||
برای ایجاد یک میانافزار، از دکوریتور `@app.middleware("http")` در بالای یک تابع استفاده میشود.
|
|
||||||
|
|
||||||
تابع میان افزار دریافت می کند:
|
|
||||||
* `درخواست`
|
|
||||||
* تابع `call_next` که `درخواست` را به عنوان پارامتر دریافت می کند
|
|
||||||
* این تابع `درخواست` را به *path operation* مربوطه ارسال می کند.
|
|
||||||
* سپس `پاسخ` تولید شده توسط *path operation* مربوطه را برمیگرداند.
|
|
||||||
* شما میتوانید سپس `پاسخ` را تغییر داده و پس از آن را برگردانید.
|
|
||||||
|
|
||||||
{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
|
|
||||||
|
|
||||||
/// نکته | به خاطر داشته باشید که هدرهای اختصاصی سفارشی را می توان با استفاده از پیشوند "X-" اضافه کرد.
|
|
||||||
|
|
||||||
اما اگر هدرهای سفارشی دارید که میخواهید مرورگر کاربر بتواند آنها را ببیند، باید آنها را با استفاده از پارامتر `expose_headers` که در مستندات <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">CORS از Starlette</a> توضیح داده شده است، به پیکربندی CORS خود اضافه کنید.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
/// توجه | جزئیات فنی
|
|
||||||
|
|
||||||
شما همچنین میتوانید از `from starlette.requests import Request` استفاده کنید.
|
|
||||||
|
|
||||||
**FastAPI** این را به عنوان یک سهولت برای شما به عنوان برنامهنویس فراهم میکند. اما این مستقیما از Starlette به دست میآید.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
### قبل و بعد از `پاسخ`
|
|
||||||
|
|
||||||
شما میتوانید کدی را برای اجرا با `درخواست`، قبل از اینکه هر *path operation* آن را دریافت کند، اضافه کنید.
|
|
||||||
|
|
||||||
همچنین پس از تولید `پاسخ`، قبل از بازگشت آن، میتوانید کدی را اضافه کنید.
|
|
||||||
|
|
||||||
به عنوان مثال، میتوانید یک هدر سفارشی به نام `X-Process-Time` که شامل زمان پردازش درخواست و تولید پاسخ به صورت ثانیه است، اضافه کنید.
|
|
||||||
|
|
||||||
{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
|
|
||||||
|
|
||||||
## سایر میان افزار
|
|
||||||
|
|
||||||
شما میتوانید بعداً در مورد میانافزارهای دیگر در [راهنمای کاربر پیشرفته: میانافزار پیشرفته](../advanced/middleware.md){.internal-link target=_blank} بیشتر بخوانید.
|
|
||||||
|
|
||||||
شما در بخش بعدی در مورد این که چگونه با استفاده از یک میانافزار، <abbr title="Cross-Origin Resource Sharing">CORS</abbr> را مدیریت کنید، خواهید خواند.
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
# امنیت
|
|
||||||
|
|
||||||
روشهای مختلفی برای مدیریت امنیت، تأیید هویت و اعتبارسنجی وجود دارد.
|
|
||||||
|
|
||||||
عموماً این یک موضوع پیچیده و "سخت" است.
|
|
||||||
|
|
||||||
در بسیاری از فریم ورک ها و سیستمها، فقط مدیریت امنیت و تأیید هویت نیاز به تلاش و کد نویسی زیادی دارد (در بسیاری از موارد میتواند 50% یا بیشتر کل کد نوشته شده باشد).
|
|
||||||
|
|
||||||
|
|
||||||
فریم ورک **FastAPI** ابزارهای متعددی را در اختیار شما قرار می دهد تا به راحتی، با سرعت، به صورت استاندارد و بدون نیاز به مطالعه و یادگیری همه جزئیات امنیت، در مدیریت **امنیت** به شما کمک کند.
|
|
||||||
|
|
||||||
اما قبل از آن، بیایید برخی از مفاهیم کوچک را بررسی کنیم.
|
|
||||||
|
|
||||||
## عجله دارید؟
|
|
||||||
|
|
||||||
اگر به هیچ یک از این اصطلاحات اهمیت نمی دهید و فقط نیاز به افزودن امنیت با تأیید هویت بر اساس نام کاربری و رمز عبور دارید، *همین الان* به فصل های بعدی بروید.
|
|
||||||
|
|
||||||
## پروتکل استاندارد OAuth2
|
|
||||||
|
|
||||||
پروتکل استاندارد OAuth2 یک مشخصه است که چندین روش برای مدیریت تأیید هویت و اعتبار سنجی تعریف می کند.
|
|
||||||
|
|
||||||
این مشخصه بسیار گسترده است و چندین حالت استفاده پیچیده را پوشش می دهد.
|
|
||||||
|
|
||||||
در آن روش هایی برای تأیید هویت با استفاده از "برنامه های شخص ثالث" وجود دارد.
|
|
||||||
|
|
||||||
این همان چیزی است که تمامی سیستم های با "ورود با فیسبوک، گوگل، توییتر، گیت هاب" در پایین آن را استفاده می کنند.
|
|
||||||
|
|
||||||
### پروتکل استاندارد OAuth 1
|
|
||||||
|
|
||||||
پروتکل استاندارد OAuth1 نیز وجود داشت که با OAuth2 خیلی متفاوت است و پیچیدگی بیشتری داشت، زیرا شامل مشخصات مستقیم در مورد رمزگذاری ارتباط بود.
|
|
||||||
|
|
||||||
در حال حاضر OAuth1 بسیار محبوب یا استفاده شده نیست.
|
|
||||||
|
|
||||||
پروتکل استاندارد OAuth2 روش رمزگذاری ارتباط را مشخص نمی کند، بلکه انتظار دارد که برنامه شما با HTTPS سرویس دهی شود.
|
|
||||||
|
|
||||||
/// نکته
|
|
||||||
|
|
||||||
در بخش در مورد **استقرار** ، شما یاد خواهید گرفت که چگونه با استفاده از Traefik و Let's Encrypt رایگان HTTPS را راه اندازی کنید.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## استاندارد OpenID Connect
|
|
||||||
|
|
||||||
استاندارد OpenID Connect، مشخصهای دیگر است که بر پایه **OAuth2** ساخته شده است.
|
|
||||||
|
|
||||||
این مشخصه، به گسترش OAuth2 میپردازد و برخی مواردی که در OAuth2 نسبتاً تردید برانگیز هستند را مشخص میکند تا سعی شود آن را با سایر سیستمها قابل ارتباط کند.
|
|
||||||
|
|
||||||
به عنوان مثال، ورود به سیستم گوگل از OpenID Connect استفاده میکند (که در زیر از OAuth2 استفاده میکند).
|
|
||||||
|
|
||||||
اما ورود به سیستم فیسبوک، از OpenID Connect پشتیبانی نمیکند. به جای آن، نسخه خودش از OAuth2 را دارد.
|
|
||||||
|
|
||||||
### استاندارد OpenID (نه "OpenID Connect" )
|
|
||||||
|
|
||||||
همچنین مشخصه "OpenID" نیز وجود داشت که سعی در حل مسائل مشابه OpenID Connect داشت، اما بر پایه OAuth2 ساخته نشده بود.
|
|
||||||
|
|
||||||
بنابراین، یک سیستم جداگانه بود.
|
|
||||||
|
|
||||||
اکنون این مشخصه کمتر استفاده میشود و محبوبیت زیادی ندارد.
|
|
||||||
|
|
||||||
## استاندارد OpenAPI
|
|
||||||
|
|
||||||
استاندارد OpenAPI (قبلاً با نام Swagger شناخته میشد) یک open specification برای ساخت APIs (که در حال حاضر جزئی از بنیاد لینوکس میباشد) است.
|
|
||||||
|
|
||||||
فریم ورک **FastAPI** بر اساس **OpenAPI** است.
|
|
||||||
|
|
||||||
این خاصیت، امکان دارد تا چندین رابط مستندات تعاملی خودکار(automatic interactive documentation interfaces)، تولید کد و غیره وجود داشته باشد.
|
|
||||||
|
|
||||||
مشخصه OpenAPI روشی برای تعریف چندین "schemes" دارد.
|
|
||||||
|
|
||||||
با استفاده از آنها، شما میتوانید از همه این ابزارهای مبتنی بر استاندارد استفاده کنید، از جمله این سیستمهای مستندات تعاملی(interactive documentation systems).
|
|
||||||
|
|
||||||
استاندارد OpenAPI شیوههای امنیتی زیر را تعریف میکند:
|
|
||||||
|
|
||||||
* شیوه `apiKey`: یک کلید اختصاصی برای برنامه که میتواند از موارد زیر استفاده شود:
|
|
||||||
* پارامتر جستجو.
|
|
||||||
* هدر.
|
|
||||||
* کوکی.
|
|
||||||
* شیوه `http`: سیستمهای استاندارد احراز هویت HTTP، از جمله:
|
|
||||||
* مقدار `bearer`: یک هدر `Authorization` با مقدار `Bearer` به همراه یک توکن. این از OAuth2 به ارث برده شده است.
|
|
||||||
* احراز هویت پایه HTTP.
|
|
||||||
* ویژگی HTTP Digest و غیره.
|
|
||||||
* شیوه `oauth2`: تمام روشهای OAuth2 برای مدیریت امنیت (به نام "flows").
|
|
||||||
* چندین از این flows برای ساخت یک ارائهدهنده احراز هویت OAuth 2.0 مناسب هستند (مانند گوگل، فیسبوک، توییتر، گیتهاب و غیره):
|
|
||||||
* ویژگی `implicit`
|
|
||||||
* ویژگی `clientCredentials`
|
|
||||||
* ویژگی `authorizationCode`
|
|
||||||
* اما یک "flow" خاص وجود دارد که میتواند به طور کامل برای مدیریت احراز هویت در همان برنامه به کار رود:
|
|
||||||
* بررسی `password`: چند فصل بعدی به مثالهای این مورد خواهیم پرداخت.
|
|
||||||
* شیوه `openIdConnect`: یک روش برای تعریف نحوه کشف دادههای احراز هویت OAuth2 به صورت خودکار.
|
|
||||||
* کشف خودکار این موضوع را که در مشخصه OpenID Connect تعریف شده است، مشخص میکند.
|
|
||||||
|
|
||||||
/// نکته
|
|
||||||
|
|
||||||
ادغام سایر ارائهدهندگان احراز هویت/اجازهدهی مانند گوگل، فیسبوک، توییتر، گیتهاب و غیره نیز امکانپذیر و نسبتاً آسان است.
|
|
||||||
|
|
||||||
مشکل پیچیدهترین مسئله، ساخت یک ارائهدهنده احراز هویت/اجازهدهی مانند آنها است، اما **FastAPI** ابزارهای لازم برای انجام این کار را با سهولت به شما میدهد و همه کارهای سنگین را برای شما انجام میدهد.
|
|
||||||
|
|
||||||
///
|
|
||||||
|
|
||||||
## ابزارهای **FastAPI**
|
|
||||||
|
|
||||||
فریم ورک FastAPI ابزارهایی برای هر یک از این شیوههای امنیتی در ماژول`fastapi.security` فراهم میکند که استفاده از این مکانیزمهای امنیتی را سادهتر میکند.
|
|
||||||
|
|
||||||
در فصلهای بعدی، شما یاد خواهید گرفت که چگونه با استفاده از این ابزارهای ارائه شده توسط **FastAPI**، امنیت را به API خود اضافه کنید.
|
|
||||||
|
|
||||||
همچنین، خواهید دید که چگونه به صورت خودکار در سیستم مستندات تعاملی ادغام میشود.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
INHERIT: ../en/mkdocs.yml
|
|
||||||
Loading…
Reference in New Issue