Class-Based Resources
Fenrir supports both Falcon-style resource controllers and Flask-style class-based views via the View and MethodView base classes.
Falcon-Style Resources
Define on_get, on_post, on_delete methods for each HTTP method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
The View Base Class
View is the base class for all class-based resources. It provides the contract that Fenrir's router expects.
Class Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
methods |
Optional[List[str]] |
None |
Allowed HTTP methods. When None, auto-detected from defined handler methods. |
provide_automatic_options |
Optional[bool] |
None |
Controls auto OPTIONS handling. None = auto-detect, True = always add OPTIONS, False = never add OPTIONS. |
dispatch_request(*args, **kwargs)
Abstract method that must be overridden by subclasses. Called by the framework when a matched route invokes this view.
1 2 3 4 5 | |
as_view(name, *class_args, **class_kwargs) (classmethod)
Creates a view function from a class that can be registered with app.add_route(). This is the bridge between class-based views and Fenrir's routing system.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
What as_view() does:
- Creates a closure that instantiates the class and calls
dispatch_request(). - Auto-detects allowed HTTP methods by inspecting the class for
get,post,put,delete,patch,options, andheadattributes. If none are found, defaults to["GET"]. - Copies
provide_automatic_optionsfrom the class to the view function. - Sets
__name__,__doc__, and__module__on the view function for introspection.
Arguments:
name— The view function name (used for debugging and URL building).*class_args, **class_kwargs— Forwarded to the class constructor on every request.
The MethodView Class
MethodView extends View with automatic HTTP method dispatch and dependency injection. Define methods named after HTTP verbs (get, post, put, delete, patch) and Fenrir routes to them automatically.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Method Resolution
MethodView.dispatch_request() resolves the handler as follows:
| HTTP Method | Handler | Fallback |
|---|---|---|
GET |
self.get() |
— |
POST |
self.post() |
— |
PUT |
self.put() |
— |
DELETE |
self.delete() |
— |
PATCH |
self.patch() |
— |
HEAD |
self.get() |
Falls back to GET handler automatically |
OPTIONS |
Auto-generated response | Returns Allow header listing all available methods |
If no handler is found for the requested method (other than HEAD/OPTIONS), a RuntimeError is raised.
HEAD Falls Back to GET
When a HEAD request arrives and no head() method is defined, MethodView automatically delegates to get(). This follows the HTTP specification where HEAD must return the same headers as GET but no body.
1 2 3 4 5 | |
Automatic OPTIONS Response
When a OPTIONS request arrives and no options() method is defined, MethodView automatically returns a 200 response with an Allow header listing all available methods:
1 2 3 4 5 6 7 8 9 10 | |
The Allow header is automatically constructed by:
- Scanning the instance for all defined HTTP method handlers (
get,post,put,delete,patch,options,head). - Adding
HEADifGETis present (since HEAD falls back to GET). - Always adding
OPTIONS. - Sorting the list alphabetically.
Dependency Injection in MethodView
MethodView integrates with Fenrir's dependency injection system via resolve_parameters(). Handler parameters are automatically resolved from path parameters, the request, and the response.
Path Parameters
Path parameters from the URL are injected into handler method parameters by name and type:
1 2 3 4 5 6 7 | |
The item_id parameter is extracted from the URL, coerced to int, and passed to get().
Request and Response Injection
The req and resp objects are available via the context, but can also be injected as parameters:
1 2 3 4 5 6 7 8 | |
Query Parameters and Body
Use Annotated with Query, Body, and other parameter markers:
1 2 3 4 5 6 7 8 9 10 11 | |
Background Tasks
BackgroundTasks is auto-injected when declared as a parameter:
1 2 3 4 5 6 7 | |
Complete Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Behavior summary:
| Route | Method | Handler | Notes |
|---|---|---|---|
GET /items |
GET | ItemListView.get |
limit defaults to 20 |
POST /items |
POST | ItemListView.post |
JSON body injected |
HEAD /items |
HEAD | ItemListView.get |
Falls back to GET |
OPTIONS /items |
OPTIONS | Auto | Returns Allow: GET, HEAD, OPTIONS, POST |
GET /items/42 |
GET | ItemDetailView.get |
item_id=42 |
PUT /items/42 |
PUT | ItemDetailView.put |
item_id=42 + JSON body |
DELETE /items/42 |
DELETE | ItemDetailView.delete |
item_id=42 |
OPTIONS /items/42 |
OPTIONS | Auto | Returns Allow: DELETE, GET, HEAD, OPTIONS, PUT |
View vs MethodView
| Feature | View |
MethodView |
|---|---|---|
| Method dispatch | Manual (dispatch_request) |
Automatic (routes to self.get, self.post, etc.) |
| Dependency injection | Manual | Automatic via resolve_parameters() |
| HEAD fallback | Manual | Automatic (falls back to GET) |
| OPTIONS handling | Manual | Automatic (returns Allow header) |
| Path params | Via req.path_params or kwargs |
Injected into handler parameters |
Use View when you need full control over dispatch. Use MethodView for the convention-over-configuration approach with automatic routing and DI.