Getting Started with App Configuration
This tutorial walks you through the configuration system of the Pagemark API. You will learn how to define environment-specific settings using the project's dataclass-based configuration hierarchy and how to apply these settings to your application.
Prerequisites
- Familiarity with Python dataclasses.
- The project structure set up with
app/config.pyandapp/__init__.py.
Step 1: Understand the Configuration Hierarchy
The application uses a hierarchical configuration system defined in app/config.py. All configurations inherit from BaseConfig, which provides default values for essential settings.
Open app/config.py to see the base definition:
@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()
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
The BaseConfig class sets up a default SECRET_KEY (falling back to "change-me" if the environment variable is missing) and uses the DEFAULT_PAGE_SIZE constant (which is 25).
Step 2: Create a Custom Configuration Override
To create a configuration for a specific environment, you inherit from BaseConfig and override the necessary fields. For example, the project already includes DevelopmentConfig for local work.
You can create a StagingConfig by adding the following to app/config.py:
@dataclass
class StagingConfig(BaseConfig):
"""Configuration for staging environments."""
DEBUG: bool = False
PAGE_SIZE: int = 50 # Larger page size for staging tests
def get_cache_config(self) -> Dict[str, Any]:
# Staging uses a larger cache than development but smaller than production
return _build_cache_config(ttl=120, max_size=512)
By overriding PAGE_SIZE, you change the default behavior of paginated endpoints. Note that BaseConfig._validate() ensures PAGE_SIZE never exceeds MAX_PAGE_SIZE (100).
Step 3: Load the Configuration in the App Factory
The application factory in app/__init__.py is designed to accept a configuration class. By default, it uses DevelopmentConfig.
def create_app(config_class=DevelopmentConfig) -> Flask:
"""Application factory."""
app = Flask(__name__)
app.config.from_object(config_class)
# ... blueprint registration ...
return app
To use your new StagingConfig, you pass it to create_app when initializing the server.
Step 4: Apply the Configuration in run.py
Update your entry point (usually run.py) to import and use your custom configuration.
from app import create_app
from app.config import StagingConfig
# Initialize the app with Staging settings
app = create_app(config_class=StagingConfig)
if __name__ == "__main__":
app.run(port=5000)
When you run this, Flask loads the attributes from StagingConfig into app.config.
Step 5: Access Configuration in Routes
Inside your route handlers, you can access these settings via current_app.config. For instance, if you wanted to use the configured PAGE_SIZE in the bookmarks list route, you would modify app/routes/bookmarks.py:
from flask import Blueprint, request, jsonify, current_app
@bookmarks_bp.route("/", methods=["GET"])
def list_bookmarks():
page = request.args.get("page", 1, type=int)
# Use the configured PAGE_SIZE as the default
per_page = request.args.get("per_page", current_app.config["PAGE_SIZE"], type=int)
# ... rest of the logic ...
Important Considerations
- Production Security: The
ProductionConfigclass inapp/config.pyis stricter thanBaseConfig. It requires theSECRET_KEYenvironment variable to be set; otherwise, it will raise aKeyErrorat startup:SECRET_KEY: str = field(default_factory=lambda: os.environ["SECRET_KEY"]) - Validation: Always call
_validate()if you are programmatically creating config instances to ensurePAGE_SIZEis within the allowedMAX_PAGE_SIZElimit. - Cache Settings: While
get_cache_config()provides environment-specific settings, be aware that theBookmarkServicecurrently initializes its internalLRUCachewith a hardcoded size of256. Overriding cache settings in config will not affect the service until the service is updated to read from the config.
Next Steps
Now that you have a custom configuration, try setting up a .env file to manage your SECRET_KEY and other environment variables, or explore app/config.py to see how TestingConfig is used to isolate test environments.