یه پروژه FastAPI ممکنه با چند تنظیم ساده شروع بشه، اما خیلی زود پای آدرس دیتابیس، کلید اتصال به سرویس ایمیل، Secret Key، دامنههای مجاز و اطلاعات سرویسهای خارجی وسط میاد. اگه همه این مقادیر مستقیم داخل فایلهای Python نوشته بشن، تغییر تنظیمات بین سیستم شخصی و سرور واقعی سخت میشه و بدتر از اون، ممکنه رمزها و کلیدهای حساس همراه سورسکد وارد Git بشن.
راه بهتر اینه که تنظیمات قابل تغییر و اطلاعات حساس رو از کد برنامه جدا کنیم. مقادیری که خارج از سورسکد نگهداری میشن و برنامه هنگام اجرا اونها رو از سیستم دریافت میکنه، با اصطلاح Environment Variables شناخته میشن. FastAPI هم برای مدیریت مرتبتر این تنظیمات میتونه از کتابخونه pydantic-settings استفاده کنه.
چرا نباید Secret Key و رمز دیتابیس داخل کد باشند؟
نوشتن یه آدرس دیتابیس داخل main.py شاید اول پروژه مشکلی ایجاد نکنه، ولی وقتی همون پروژه روی سرور Deploy میشه معمولاً تنظیمات تغییر میکنن. دیتابیس Development با Production یکی نیست، کلیدهای سرویس پرداخت متفاوتن و حتی ممکنه چند محیط جدا برای تست و نسخه اصلی داشته باشید.
اگه این اطلاعات داخل کد باشن، برای هر محیط باید فایلهای پروژه رو تغییر بدید و احتمال اشتباه هم بیشتر میشه. مشکل جدیتر زمانی اتفاق میفته که Password، Token یا Secret Key داخل Repository ثبت بشه؛ حتی اگه بعداً خط رو پاک کنید، ممکنه مقدار قبلی همچنان داخل تاریخچه Git باقی مونده باشه.
پس بهتره سورسکد فقط بدونه «به یه DATABASE_URL نیاز دارم»، نه اینکه مقدار واقعی اون رو داخل خودش نگهداری کنه.
Environment Variable دقیقاً چیست؟
به زبان ساده، سیستمعامل میتونه یه سری مقدار خارج از برنامه نگه داره و هنگام اجرای برنامه در اختیارش قرار بده. به این متغیرهای تنظیماتی خارج از کد گفته میشه که اسم رایجشون Environment Variable هست.
مثلاً میشه روی سرور مقدار DATABASE_URL رو برای دیتابیس اصلی و روی لپتاپ توسعهدهنده مقدار متفاوتی برای دیتابیس محلی تعریف کرد، بدون اینکه حتی یه خط از کد FastAPI تغییر کنه.
خود FastAPI هم استفاده از Environment Variableها رو برای تنظیماتی مثل Secret Key، اطلاعات دیتابیس و سرویسهای خارجی پیشنهاد میکنه، چون این مقادیر معمولاً بین محیطها تغییر میکنن یا ماهیت حساس دارن.
pydantic-settings چه مشکلی را حل میکند؟
Environment Variableها در سطح سیستم به صورت متن در اختیار برنامه قرار میگیرن. اما داخل FastAPI ممکنه بعضی تنظیمات عدد، Boolean یا ساختار مشخصی داشته باشن و همینجا نیاز داریم مقدارها قبل از استفاده بررسی و تبدیل بشن.
pydantic-settings اجازه میده یه کلاس برای تنظیمات پروژه تعریف کنیم، نوع هر مقدار رو مشخص کنیم و بعد هنگام ساخت اون کلاس، مقادیر از Environment Variableها یا فایل .env خونده بشن. Pydantic بعد از دریافت این مقادیر، تبدیل نوع و بررسی اعتبار اونها رو انجام میده؛ بنابراین مثلاً مقداری که برای یه تنظیم int تعریف شده، به شکل عدد داخل برنامه در دسترس خواهد بود.
استفاده از فایل .env در FastAPI
در محیط توسعه معمولاً تعریف دستی چندین Environment Variable روی سیستم راحت نیست، به همین دلیل میشه اونها رو داخل یه فایل مخصوص تنظیمات قرار داد که معمولاً .env نام داره.
این فایل میتونه شامل چیزهایی مثل URL دیتابیس، Secret Key و نام محیط اجرای برنامه باشه و pydantic-settings هم میتونه اون رو مستقیماً بخونه. برای این قابلیت، تنظیم فایل ورودی با SettingsConfigDict انجام میشه.
یه ساختار ساده میتونه این شکلی باشه:
# .env
APP_NAME="My FastAPI App"
DATABASE_URL="postgresql://user:password@localhost/app"
SECRET_KEY="change-this-secret"
DEBUG=true
# app/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
app_name: str
database_url: str
secret_key: str
debug: bool = False
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8"
)
settings = Settings()
# app/main.py
from fastapi import FastAPI
from app.config import settings
app = FastAPI(
title=settings.app_name
)
@app.get("/info")
async def get_info():
return {
"app_name": settings.app_name,
"debug": settings.debug
}
اینجا فایل Python فقط مشخص میکنه برنامه چه تنظیماتی لازم داره و نوع هرکدوم چیه، ولی مقدار واقعی اونها بیرون از منطق اصلی پروژه قرار گرفته. وقتی برنامه روی سرور واقعی اجرا بشه هم میتونید به جای .env، همون مقادیر رو مستقیماً به صورت Environment Variable روی سیستم یا سرویس Hosting تنظیم کنید.
فایل .env را داخل Git نگذارید
جدا کردن Secretها از Python زمانی فایده داره که دوباره همون اطلاعات رو همراه Repository منتشر نکنیم. اگه فایل .env شامل رمز دیتابیس و Secret Key باشه، معمولاً باید داخل .gitignore قرار بگیره تا به Git اضافه نشه.
برای اینکه اعضای تیم بدونن چه متغیرهایی لازمه، میشه یه فایل نمونه مثل .env.example ساخت که فقط اسم تنظیمات رو داشته باشه و مقدارهای واقعی داخلش قرار نگیرن. اینطوری ساختار تنظیمات پروژه مشخص میمونه، ولی Secret واقعی منتشر نمیشه.
اگه یه Secret به اشتباه Commit شد، فقط حذف کردنش از فایل کافی نیست؛ بهتره اون کلید یا رمز رو عوض کنید، چون از اون لحظه باید فرض کنید مقدار قبلی دیگه امن نیست.
Development و Production را چطور جدا کنیم؟
یکی از اصلیترین مزیتهای این ساختار اینه که سورسکد در محیطهای مختلف همون سورسکد باقی میمونه. روی سیستم توسعه میتونید DEBUG=true و دیتابیس محلی داشته باشید، در حالی که روی سرور واقعی DEBUG=false و URL دیتابیس اصلی تنظیم شده.
یعنی تفاوت محیطها داخل تنظیمات قرار میگیره، نه داخل شرطهای عجیب در چند فایل مختلف پروژه. این موضوع Deploy رو قابل پیشبینیتر میکنه و احتمال اینکه تنظیم آزمایشی ناخواسته روی سرور واقعی باقی بمونه کمتر میشه.
چرا Settings بهتر از خواندن دستی os.environ است؟
خوندن مستقیم Environment Variableها با ابزارهای استاندارد Python ممکنه و برای چند مقدار ساده مشکلی نداره، اما وقتی تعداد تنظیمات زیاد بشه باید خودتون نبودن مقدار، تبدیل نوع و مقدار پیشفرض رو مدیریت کنید.
با BaseSettings میشه این قوانین رو کنار خود تنظیمات تعریف کرد. اگه یه مقدار اجباری وجود نداشته باشه یا نوع اون درست نباشه، خطا خیلی زود و هنگام بالا اومدن برنامه مشخص میشه؛ این رفتار معمولاً خیلی بهتر از اینه که برنامه اجرا بشه و چند دقیقه بعد وسط یه Request تازه بفهمیم تنظیم حیاتی وجود نداشته.
Settings را یک بار بسازیم یا در هر Request؟
تنظیمات معمولاً هنگام اجرای برنامه تغییر نمیکنن، بنابراین منطقی نیست فایل .env یا Environment Variableها برای هر Request دوباره پردازش بشن. مستندات FastAPI برای ساخت تنظیمات از طریق Dependency هم استفاده از Cache رو مطرح میکنن تا Object تنظیمات یک بار ساخته و بعد دوباره استفاده بشه. این روش مخصوصاً وقتی تستها نیاز به جایگزین کردن Settings دارن کاربردیه.
برای پروژههای ساده، ساخت یه Object مشترک مثل settings = Settings() کاملاً قابلفهمه و وقتی معماری پروژه بزرگتر شد میشه مدیریت اون رو به Dependency جدا منتقل کرد.
Secretها فقط داخل .env امن نمیشوند
فایل .env فقط کمک میکنه Secret از سورسکد جدا بشه؛ خودش سیستم امنیتی جادویی نیست. اگه فایل روی سرور برای همه قابل دسترسی باشه، داخل Backup عمومی قرار بگیره یا اشتباهی Upload بشه، اطلاعات همچنان ممکنه لو برن.
در پروژههای بزرگتر معمولاً Secretها مستقیماً از تنظیمات محیط Hosting، Docker، Kubernetes یا سرویسهای مخصوص مدیریت Secret دریافت میشن و فایل .env بیشتر برای Development محلی استفاده میشه.
پس اصل مهم اینه که کد برنامه به Secret وابسته باشه، ولی مالک مقدار Secret نباشه.
جمعبندی
مدیریت Environment Variables در FastAPI باعث میشه تنظیمات پروژه از منطق اصلی برنامه جدا بمونن و مجبور نباشید برای تغییر دیتابیس، Secret Key یا تنظیمات محیط، سورسکد رو ویرایش کنید. pydantic-settings هم این فرآیند رو مرتبتر میکنه و اجازه میده نوع و مقدار مورد انتظار هر تنظیم رو داخل یه کلاس مشخص تعریف کنید.
فایل .env برای محیط توسعه راه سادهای برای نگهداری این مقادیره، اما نباید شامل Secretهای واقعی داخل Git بشه. روی سرور هم بهتره تنظیمات واقعی از محیط اجرا دریافت بشن تا همون کد بدون تغییر در Development، Testing و Production قابل استفاده باشه.
قاعده ساده اینه: تنظیمات قابل تغییر و اطلاعات حساس رو از کد بیرون بکش؛ کد باید بدونه چه مقداری لازم داره، نه اینکه Secret واقعی داخل خودش داشته باشه.
نظرات کاربران (0)