본문 바로가기

개발자 생활

FastAPI 연재 3편 — .env + pydantic-settings로 “설정 지옥” 탈출하기

반응형

FastAPI 프로젝트에서 설정을 대충 시작하면 보통 이렇게 된다.

  • 코드 여기저기에 os.getenv(...) 난사
  • 로컬에서는 되는데 도커에서 안 됨
  • 테스트에서 설정 바꾸기 귀찮아서 결국 전역 변수로 땜빵

나도 예전에 다 해봤고… 그래서 이번 프로젝트에서는 처음부터 Settings 클래스로 통제했다.


핵심: Settings(BaseSettings) 하나로 끝내기

대표 이미지 (Settings / .env / prefix)

pydantic-settingsBaseSettings를 쓰면, 환경변수 로딩/타입 검증/기본값을 한 번에 잡을 수 있다.

내가 쓴 구조는 이런 느낌.

class Settings(BaseSettings):
    app_name: str = "Doubles API"
    api_v1_prefix: str = "/api/v1"
    log_level: str = "info"
    database_url: str = Field(default_factory=...)
    gemini_api_key: str | None = None
    weather_api_key: str | None = None

    model_config = SettingsConfigDict(
        env_file=".env",
        env_prefix="DOUBLES_",
        case_sensitive=False,
        extra="ignore",
    )

여기서 학습 포인트는 3개.


1) .env는 “로컬 개발 편의”용이다

env_file=".env" 덕분에, 로컬에서는 .env만 만들어두면 된다.

예시 템플릿은 .env.example에 있다.

DOUBLES_APP_NAME=Doubles API
DOUBLES_API_V1_PREFIX=/api/v1
DOUBLES_LOG_LEVEL=info

DOUBLES_DATABASE_URL=sqlite:////Users/your-name/.doubles/server/doubles.db
DOUBLES_GEMINI_API_KEY=your-gemini-api-key
DOUBLES_WEATHER_API_KEY=your-weatherapi-key

포인트는 딱 하나: 키 이름에 규칙(prefix)을 줘라.


2) env_prefix="DOUBLES_"는 팀 작업할 때 진짜 편하다

환경변수가 프로젝트마다 섞이면 진짜 멘붕 오는데, prefix를 통일하면 된다.

  • DOUBLES_DATABASE_URL
  • DOUBLES_GEMINI_API_KEY
  • DOUBLES_WEATHER_API_KEY

나중에 CI나 서버 배포할 때도 “이 프로젝트 변수가 뭔지”가 너무 선명해진다.


3) Settings는 캐시해두는 게 깔끔하다

“환경별 설정 주입” 장면

Settings는 보통 “프로세스 시작할 때 한 번” 로드하면 끝이다.

그래서 lru_cache로 캐싱.

@lru_cache
def get_settings() -> Settings:
    return Settings()

이러면 코드 어디서든 get_settings()만 부르면 같은 인스턴스를 계속 쓰게 된다.


실습: 일부러 API 키를 빼보고 503 확인하기

이 프로젝트는 API 키가 없으면 서비스를 꺼버리는 형태로 설계돼 있다.

  • Gemini 키 없으면 AI 일기 생성 기능은 503
  • Weather 키 없으면 날씨 조회는 503

.env에서 DOUBLES_WEATHER_API_KEY를 지우고,

curl -sS "http://127.0.0.1:8000/api/v1/weather?lat=37.57&lng=126.98"

503이 떨어지면 “설정 → DI → 라우터” 흐름이 제대로 붙었다는 뜻이다.


마무리

설정은 초반에 대충 하면, 후반에 무조건 갚는다. (이건 진리임)
pydantic-settings타입/기본값/환경변수 규칙을 초기에 잡아두면, 프로젝트가 커질수록 편해진다.

다음 편에서는 라우팅 구조를 본다. root 라우터랑 /api/v1를 왜 나눴는지.


참고

반응형