FastAPI Settings
Application Kit provides a settings system for FastAPI applications that bridges Bender configuration with a type-safe Settings object.
Overview
The settings system allows you to:
- Define service-specific configuration by subclassing
Settings - Bridge Bender manifest values to FastAPI settings via
get_configuration() - Access settings dynamically via
get_settings() - Override settings in tests without modifying code
Bridging Bender Config to FastAPI
The key pattern is to declare settings attributes, then populate them from Bender configuration at startup:
"""FastAPI settings configuration example.
This example shows how to subclass Settings, register it, and populate
values from Bender configuration in your application's __init__.py.
"""
import os
from application_kit.fastapi.settings import Settings, get_settings, register_settings
from application_kit.settings import get_configuration
class MyServiceSettings(Settings):
"""Custom settings for my service.
Declare attributes without defaults - they will be configured at startup.
These values can be accessed via get_settings() throughout your app.
"""
# Service-specific settings (populated from Bender manifest)
MAX_RESULTS_PER_PAGE: int
CACHE_TTL_SECONDS: int
EXTERNAL_API_KEY: str
# Environment-based settings
DEVELOPMENT: bool
# Register the settings instance
register_settings(MyServiceSettings())
# Bridge Bender configuration to FastAPI settings
get_settings().configure("MAX_RESULTS_PER_PAGE", get_configuration("MAX_RESULTS_PER_PAGE"))
get_settings().configure("CACHE_TTL_SECONDS", get_configuration("CACHE_TTL_SECONDS"))
get_settings().configure("EXTERNAL_API_KEY", get_configuration("EXTERNAL_API_KEY"))
# Environment variables
get_settings().configure("DEVELOPMENT", os.environ.get("DEVELOPMENT", "no") == "yes")
This bridges two systems:
| Source | Method | Example |
|---|---|---|
| Bender manifest | get_configuration() |
Database URLs, API keys, feature flags |
| Environment variables | os.environ.get() |
DEVELOPMENT, DEBUG |
Bender Manifest Configuration
Add your settings to application.json:
{
"configurations": [
{"name": "MAX_RESULTS_PER_PAGE", "type": "int", "test_value": 100},
{"name": "CACHE_TTL_SECONDS", "type": "int", "test_value": 300},
{"name": "EXTERNAL_API_KEY", "type": "string", "test_value": "test-key"}
]
}
Using Settings
Always fetch settings dynamically
Never store settings in module-level variables or class attributes. Always call get_settings() when you need a value. This ensures test overrides work correctly.
"""FastAPI settings usage example.
Shows how to access settings and configuration in your application code.
"""
from bender.shared.manifest.types import RateLimitMode
from fastapi import APIRouter
from application_kit.fastapi.settings import Settings, get_settings
from application_kit.settings import get_configuration
router = APIRouter()
@router.get("/search")
async def search() -> dict[str, str | None]:
"""Example endpoint that uses settings.
Always call get_settings() when you need settings values.
This ensures overrides (e.g., in tests) are respected.
"""
# Fetch settings dynamically each time
settings = get_settings()
return {
"product": settings.PRODUCT.value if settings.PRODUCT else None,
}
# BAD: Don't do this - settings won't reflect runtime overrides
# _cached_settings = get_settings() # WRONG!
# Configuration values from manifest
def is_rate_limit_disabled() -> bool:
"""Check if rate limiting is disabled using manifest configuration."""
mode: RateLimitMode = get_configuration("RATE_LIMIT_MODE")
return mode == RateLimitMode.off
# Custom Settings subclass example
class MyAppSettings(Settings):
"""Custom settings for your application."""
MY_CUSTOM_SETTING: str = "default_value"
Built-in Settings
The base Settings class provides these settings:
| Setting | Type | Default | Description |
|---|---|---|---|
PRODUCT |
Products \| None |
None |
Default product for authentication |
DISABLE_RATE_LIMIT |
bool |
False |
Disable rate limiting globally |
Testing with Settings
Override settings in tests using the decorator or context manager:
"""FastAPI settings testing example.
Shows how to override settings in tests.
"""
from collections.abc import Generator
import pytest
from application_kit.fastapi.settings import SettingsOverride, override_settings
@override_settings(DISABLE_RATE_LIMIT=True)
def test_with_rate_limit_disabled() -> None:
"""Use the decorator to override settings for a test function."""
# Rate limiting is disabled for this test
pass
def test_with_context_manager() -> None:
"""Use the context manager for fine-grained control."""
# Default settings apply here
with SettingsOverride(DISABLE_RATE_LIMIT=True):
# Rate limiting disabled in this block
pass
# Default settings apply again
@pytest.fixture
def disabled_rate_limit() -> Generator[None, None, None]:
"""Fixture that disables rate limiting."""
with SettingsOverride(DISABLE_RATE_LIMIT=True):
yield
Best Practices for Testing
- Use
@override_settingsdecorator for test functions that need settings changed for the entire test - Use
SettingsOverridecontext manager when you need to test both default and overridden behavior - Create fixtures for commonly overridden settings
API Reference
application_kit.fastapi.settings
Settings
Settings()
Source code in application_kit/fastapi/settings.py
12 13 | |
SettingsOverride
SettingsOverride(**overrides)
Source code in application_kit/fastapi/settings.py
36 37 | |
register_settings
register_settings(settings)
Used to register a subclass of settings with additional configurations
Source code in application_kit/fastapi/settings.py
56 57 58 | |
get_settings
get_settings()
Source code in application_kit/fastapi/settings.py
61 62 | |
override_settings
override_settings(**overrides)
Source code in application_kit/fastapi/settings.py
65 66 67 68 69 70 71 72 73 74 | |