Advanced Features
Dev Mode Debug Pages
Enable detailed debug pages with stack traces, source context, and vendor frame toggling for development:
1 2 3 4 5 6 7 | |
When an unhandled exception occurs in dev mode, Fenrir renders a beautiful debug page showing:
- Full stack trace with syntax-highlighted source code
- Local variables at each frame
- Source context (surrounding lines) for each frame
- Vendor frame toggle (hide/show library internals)
- Request details (method, path, headers, query params)
Warning: Never enable
dev_modein production — it exposes sensitive information including source code, variable values, and internal paths.
WSGI Application Mounting
Mount legacy WSGI applications:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Framework Compatibility Modes
Bottle Compatibility
1 2 3 4 5 6 7 | |
Falcon Compatibility
1 2 3 4 5 6 | |
Sanic Compatibility
1 2 3 4 5 6 | |
Response Models
1 2 3 4 5 6 7 8 9 10 | |
Multiple Response Models per Status
Apply different response models based on the actual response status code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Response Model Filtering
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Event Listeners
1 2 3 4 5 6 7 | |
Connection Pooling
Built-in generic connection pooling for databases and external services:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Parameters:
create_func: Callable that creates a new connectionclose_func: Callable that closes a connection (optional)min_size: Minimum pool size (default:1)max_size: Maximum pool size (default:10)max_idle_seconds: Max idle time before recycling (default:300)max_lifetime_seconds: Max connection lifetime (default:3600)health_check_interval: Interval between health checks (default:60)retry_attempts: Number of retry attempts on failure (default:3)retry_backoff: Base backoff multiplier for retries (default:0.5)validate_func: Optional callable to validate a connection is still healthy; can be sync or async (default:None)
ConnectionPool API:
await pool.initialize()— Initialize the pool and pre-fill withmin_sizeconnections. Called automatically on firstacquire().await pool.acquire()— Acquire a connection (async context manager). Returns a connection object.await pool.close()— Close all connections in the pool.pool.stats— Property returning a dict withactive,idle, andmax_sizecounts.
DatabasePool
Extends ConnectionPool with built-in query retry logic:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
DatabasePool API (in addition to ConnectionPool):
await pool.execute_with_retry(func, *args, retries=None, **kwargs)— Execute a function with automatic retry and exponential backoff. Acquires a connection, callsfunc(conn, *args, **kwargs), and retries on failure. Theretriesparameter overrides the pool'sretry_attempts.
HTTP/2 Server Push
Proactively push resources to clients before they request them:
1 2 3 4 5 6 7 8 9 10 | |
Parameters:
as_header: IfTrue(default), push promises are sent viaLinkheaders. IfFalse, the response body is returned as-is without headers.
HTTP2Push API:
push.push(content, push_paths=None)— Return aResponsewithLinkheaders for HTTP/2 push promises. Ifpush_pathsis not provided, uses the paths added viaadd_push_path(). Content can be a string (wrapped as HTML), dict/list (wrapped as JSON), or aResponseobject.push.add_push_path(path)— Add a path to the auto-push list. Returnsselffor chaining.push.clear_push_paths()— Clear all auto-push paths. Returnsselffor chaining.@push.auto_push(static_url="/static", paths=None)— Decorator that automatically pushes static assets.pathsis a list of file paths relative tostatic_urlto push. IfpathsisNone, no paths are pushed (useadd_push_path()first).
Chainable push path setup:
1 2 3 4 5 6 | |
Auto-push decorator:
1 2 3 | |
Note: HTTP/2 push requires the ASGI server to support HTTP/2 (e.g., Uvicorn with h2, Daphne, or Hypercorn). If the server does not support HTTP/2, push promises are silently ignored.
Signals
Fenrir includes a signal system for event-driven communication between components. Signals are similar to Blinker's pattern.
signal() function
Get or create a named signal on the global signal bus:
1 2 3 4 | |
Namespace class
A Namespace is a dict-like container for organizing signals. The global namespace is exposed as signal_bus:
1 2 3 4 | |
Signal API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Built-in signals
request_started— Fired before a request is processed.request_finished— Fired after a response is prepared.got_request_exception— Fired when an exception occurs during request handling.template_rendered— Fired after a template is rendered.
1 2 3 4 5 6 7 8 9 | |
Async signal receivers
Async receivers are automatically scheduled as background tasks when the signal is sent. If no event loop is running, async receivers are skipped with a debug log.
1 2 3 | |
AppContext and RequestContext
Context managers for accessing application and request-level data outside of request handling.
AppContext
Sets the current application context. Use current_app proxy to access it:
1 2 3 4 | |
On exit, do_teardown_appcontext() is called, running all registered teardown functions.
RequestContext
Sets both the application and request context. Use request and g proxies to access them:
1 2 3 4 5 | |
Global proxies:
request— The current request object (available insideRequestContext)g— A namespace for storing per-request temporary datacurrent_app— The current application object (available insideAppContext)session— The session object (available insideRequestContext)
Testing Utilities
app.test_client()
Create a test client for making requests without running a server:
1 2 3 4 5 6 7 8 | |
app.test_request_context()
Create a request context for testing code that accesses request or g:
1 2 3 4 | |
OpenAPI Schema Generation
Generate an OpenAPI 3.0.3 schema from your registered routes:
1 2 | |
The schema is automatically cached and invalidated when routes are added. Built-in endpoints are served at the configured URLs:
openapi_url(default:/openapi.json) — The raw schemadocs_url(default:/docs) — Swagger UIredoc_url(default:/redoc) — ReDoc
1 | |
Background Tasks
Schedule coroutines to run in the background:
1 2 3 4 | |
add_task() accepts either a coroutine function (which is automatically called) or an already-created coroutine object. Returns an asyncio.Task.
Error Handlers
Register custom error handlers for exceptions or HTTP status codes:
1 2 3 4 5 6 7 8 9 10 11 | |
Handlers can be registered for multiple exceptions or status codes in a single decorator call.
App Context Teardown
Register functions to run when the application context is torn down:
1 2 3 4 5 6 | |
Teardown functions are called in reverse order of registration. They receive the exception (if any) as an argument. This is useful for releasing resources like database connections or file handles.