엔터프라이즈 FastAPI 앱을 위한 10개의 Python 패키지 구축: 내가 배운 점

발행: (2025년 12월 17일 오전 09:20 GMT+9)
8 min read
원문: Dev.to

Source: Dev.to – Building 10 Python Packages for Enterprise FastAPI Apps: What I Learned

Cover image for “Building 10 Python Packages for Enterprise FastAPI Apps: What I Learned”

Daniel Garza

1년 동안 엔터프라이즈 플랫폼을 구축하면서, 나는 같은 문제들을 계속해서 해결하고 있었다:

  • 실제로 확장 가능한 RBAC와 함께 JWT 인증을 어떻게 처리할까?
  • 왜 모든 프로젝트마다 자체 로깅 설정이 필요할까?
  • Azure Key Vault와 로컬 개발 환경에서 비밀 정보를 어떻게 관리할까?
  • 데이터베이스 연결 풀링을 가장 깔끔하게 처리하는 방법은?

그래서 나는 이러한 패턴들을 10개의 재사용 가능한 패키지로 추출하고 오픈소스로 공개했다.

Netrun 서비스 라이브러리

모든 패키지는 MIT‑라이선스를 따르며 PyPI에서 사용할 수 있습니다:

pip install netrun-auth netrun-logging netrun-config

기본 레이어

netrun-logging – 구조화된 로깅, 이제는 별로 안 지루하게

  • structlog 기반으로 표준 라이브러리 대비 약 2.9× 성능 향상.
  • 주요 기능: 민감한 필드 자동 마스킹.
from netrun_logging import get_logger

logger = get_logger(__name__)

# The password field is automatically redacted
logger.info(
    "user_login",
    username="daniel",
    password="secret123",   # Logged as "password": "[REDACTED]"
    ip_address="192.168.1.1",
)

netrun-errors – HTTP와 매핑되는 예외 계층 구조

  • Exception 대신 타입이 지정된 오류를 사용합니다.
  • 각 오류 클래스는 해당 HTTP 상태 코드와 매핑됩니다.
from netrun_errors import NotFoundError, ValidationError
from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
async def get_user(user_id: str):
    user = await db.get_user(user_id)
    if not user:
        # Raises a 404 response automatically
        raise NotFoundError("User", user_id)
    return user

인증 레이어

netrun-auth – JWT + RBAC + 멀티‑테넌트 격리

가장 어려운 구성 요소였습니다. 정책 기반 접근 제어를 위해 Casbin을 사용합니다.

from netrun_auth import JWTAuthenticator, require_permission

auth = JWTAuthenticator(
    secret_key="your-secret",
    algorithm="HS256"
)

@app.get("/admin/users")
@require_permission("users:read")
async def list_users(user=Depends(auth.get_current_user)):
    # Only users with the `users:read` permission can access this endpoint
    return await get_users()

멀티‑테넌트 격리를 통해 사용자는 자신이 속한 테넌트의 데이터만 접근할 수 있습니다:

@require_tenant_access
async def get_tenant_data(tenant_id: str, user=Depends(auth.get_current_user)):
    # Automatically validates: user.tenant_id == tenant_id
    return await db.get_tenant_data(tenant_id)
  • JWTAuthenticator – 토큰 생성/검증을 담당합니다.
  • require_permission – 필요한 Casbin 권한을 확인하는 데코레이터입니다.
  • require_tenant_access – 테넌트 수준 격리를 강제하는 데코레이터입니다.

Config 레이어

netrun-config – Azure Key Vault와 로컬 폴백

프로덕션에서는 Azure Key Vault를 사용하고 로컬에서는 .env 파일을 사용합니다:

from netrun_config import AzureKeyVaultConfig

config = AzureKeyVaultConfig(
    vault_url="https://my-vault.vault.azure.net",
    cache_ttl=300,  # Cache secrets for 5 minutes
)

# In production: fetches from Key Vault
# Locally: falls back to environment variables
db_password = await config.get_secret("database-password")
  • 프로덕션 – 비밀은 Azure Key Vault에서 직접 가져옵니다.
  • 로컬 개발 – Vault에 접근할 수 없을 경우, 구성은 환경 변수(예: .env 파일에서 로드된 변수)로 대체됩니다.

LLM 레이어

netrun-llm – 다중 제공자 오케스트레이션

netrun‑llm은 LLM 제공자 간의 차이를 추상화하여, 원활하게 전환하거나 백업할 수 있게 합니다.

from netrun_llm import LLMOrchestrator

llm = LLMOrchestrator(
    providers=["azure-openai", "ollama", "claude"],
    fallback_enabled=True,
)

# Automatically fails over if the primary provider is down
response = await llm.complete(
    prompt="Summarize this document",
    model="gpt-4",
    fallback_model="llama2",  # Use Ollama if Azure is down
)

데이터 레이어

netrun-db-pool – 연결 폭풍을 처리하는 비동기 SQLAlchemy

자동 건강 검사를 포함한 연결 풀링

from netrun_db_pool import DatabasePool

pool = DatabasePool(
    url="postgresql+asyncpg://...",
    pool_size=20,
    max_overflow=10,
    health_check_interval=30,
)

async with pool.session() as session:
    result = await session.execute(query)
  • url – 데이터베이스 연결 문자열.
  • pool_size – 영구적으로 유지되는 연결 수.
  • max_overflow – 풀에 연결이 부족할 때 생성될 수 있는 추가 연결 수.
  • health_check_interval – 연결을 유지하기 위한 자동 건강 검사 ping 간격(초).

디자인 철학

소프트 의존성

각 패키지는 독립적으로 동작하지만, 여러 패키지를 함께 설치하면 자동으로 서로 통합됩니다:

패키지결과
netrun-auth + netrun-logging인증 이벤트가 자동으로 기록됩니다
netrun-config + netrun-logging비밀 접근이 감사됩니다
netrun-db-pool + netrun-errors연결 오류가 타입으로 표시됩니다

통합은 간단한 탐지 패턴을 사용해 런타임에 수행됩니다:

try:
    from netrun_logging import get_logger
    logger = get_logger(__name__)
except ImportError:                     # Fallback to the standard library
    import logging
    logger = logging.getLogger(__name__)

제로 설정 기본값

모든 패키지는 합리적인 기본값을 제공하므로 별도의 설정 없이 바로 사용할 수 있습니다:

from netrun_auth import JWTAuthenticator

# 바로 사용할 수 있음
auth = JWTAuthenticator()

# 필요할 때 전체 커스터마이징
auth = JWTAuthenticator(
    secret_key="…",
    algorithm="RS256",
    issuer="my-app",
    audience=["api", "web"]
)

테스트 우선

netrun-pyte – 테스트‑우선 유틸리티로, 스위트에 포함되어 있습니다(내용은 간략히 생략).

…여기에 테스트 접근 방식에 대한 추가 세부 사항이 이어집니다…

st‑fixtures – 통합 테스트 픽스처

# conftest.py
pytest_plugins = ["netrun_pytest_fixtures"]

# Your tests automatically get:
# - mock_auth:   Pre‑configured auth bypass
# - mock_db:     In‑memory SQLite
# - mock_config: Environment‑based config
# - mock_llm:    Deterministic LLM responses

다음에 할 일

저는 이 패키지들을 적극적으로 유지 보수하고 있습니다. 현재 우선순위는 다음과 같습니다:

  • 더 나은 문서화 – READMEs는 시작에 불과하지만, 전체 문서 사이트가 곧 제공될 예정입니다.
  • 더 많은 LLM 제공자 – Anthropic Claude API, Google Gemini 등 추가 중입니다.
  • OpenTelemetry 추적 – 모든 패키지에 걸친 통합 추적.

시도해 보기

pip install netrun-auth netrun-logging netrun-config

GitHub: https://github.com/your‑org/st‑fixtures
PyPI: https://pypi.org/project/st‑fixtures/

MIT 라이선스. 이슈와 PR을 환영합니다!

FastAPI 애플리케이션에서 교차 관심사에 대해 어떤 패턴을 사용하시나요? 제가 놓친 부분을 알려주시면 좋겠습니다.

Back to Blog

관련 글

더 보기 »