Introduction to Application Configuration
etchblok-test-api uses a class-based configuration system to manage environment-specific settings like security keys, pagination limits, and cache behavior. By leveraging Python dataclasses and inheritance, the project ensures that shared defaults are maintained in a single location while allowing strict overrides for production and testing environments.
Environment-Based Configuration
The configuration is structured around a hierarchy of classes in app/config.py. This approach allows you to switch between local development, automated testing, and production deployments by passing the appropriate class to the application factory.
The Base Configuration
The BaseConfig class serves as the source of truth for all shared settings. It defines the default behavior for the application, including pagination and security defaults.
@dataclass
class BaseConfig:
"""Base configuration shared across all environments."""
SECRET_KEY: str = field(default_factory=lambda: os.environ.get("SECRET_KEY", "change-me"))
DEBUG: bool = False
TESTING: bool = False
PAGE_SIZE: int = DEFAULT_PAGE_SIZE
def get_cache_config(self) -> Dict[str, Any]:
"""Return cache settings for this environment."""
return _build_cache_config()
Key constants used by BaseConfig include:
DEFAULT_PAGE_SIZE: Set to 25.MAX_PAGE_SIZE: Set to 100, used for internal validation.API_VERSION: Set to "v1".
Environment Overrides
etchblok-test-api provides three specialized subclasses of BaseConfig:
- DevelopmentConfig: Enables
DEBUGmode and reduces thePAGE_SIZEto 10 for easier manual testing of pagination. It also configures a smaller, short-lived cache (30s TTL, 128 entries). - TestingConfig: Sets
TESTINGtoTrueand uses a minimalPAGE_SIZEof 5 to isolate test cases. - ProductionConfig: Enforces strict security. Unlike other environments, it will raise a
KeyErrorif theSECRET_KEYenvironment variable is missing, as it does not provide a default value. It also scales the cache to 4096 entries with a 600s TTL.
@dataclass
class ProductionConfig(BaseConfig):
"""Configuration for production deployments."""
# Enforces that SECRET_KEY must be in the environment
SECRET_KEY: str = field(default_factory=lambda: os.environ["SECRET_KEY"])
PAGE_SIZE: int = DEFAULT_PAGE_SIZE
def get_cache_config(self) -> Dict[str, Any]:
return _build_cache_config(ttl=600, max_size=4096)
Loading Configuration
The configuration is applied during application startup in the create_app factory function located in app/__init__.py. Flask's app.config.from_object() method reads the attributes of the provided class and populates the app.config dictionary.
To initialize the app with a specific configuration, pass the class to the factory:
from app import create_app
from app.config import ProductionConfig
# Initialize for production
app = create_app(config_class=ProductionConfig)
By default, create_app uses DevelopmentConfig if no argument is provided.
Internal Validation
The BaseConfig class includes a _validate() method designed to check internal invariants, such as ensuring the SECRET_KEY is present and the PAGE_SIZE does not exceed the MAX_PAGE_SIZE limit:
def _validate(self) -> bool:
"""Check internal invariants. Not part of the public API."""
return bool(self.SECRET_KEY) and self.PAGE_SIZE <= MAX_PAGE_SIZE
Note that this method is marked as internal and is not automatically invoked by the Flask framework during startup.
Implementation Gotchas
While the configuration system provides a centralized way to manage settings, some components in etchblok-test-api currently bypass these settings:
- Hardcoded Cache Size: Although
BaseConfigand its subclasses provide aget_cache_config()method, theBookmarkServiceinapp/services/bookmark_service.pycurrently hardcodes itsLRUCachesize to 256 entries during initialization:# app/services/bookmark_service.py
def _init_services(self) -> None:
self._repo = BookmarkRepository()
self._cache: LRUCache[Bookmark] = LRUCache(max_size=256) # Hardcoded
self._search = SearchIndex(self._repo) - Production Secret Key: If you attempt to start the application using
ProductionConfigwithout setting theSECRET_KEYenvironment variable, the application will fail to start with aKeyError. Always ensure your environment is configured before deployment.