Skip to main content

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.py and app/__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 ProductionConfig class in app/config.py is stricter than BaseConfig. It requires the SECRET_KEY environment variable to be set; otherwise, it will raise a KeyError at startup:
    SECRET_KEY: str = field(default_factory=lambda: os.environ["SECRET_KEY"])
  • Validation: Always call _validate() if you are programmatically creating config instances to ensure PAGE_SIZE is within the allowed MAX_PAGE_SIZE limit.
  • Cache Settings: While get_cache_config() provides environment-specific settings, be aware that the BookmarkService currently initializes its internal LRUCache with a hardcoded size of 256. 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.