Building RESTful APIs with MethodView
To implement a RESTful API in this project, you can subclass MethodView from flask.views. This class automatically dispatches incoming HTTP requests to instance methods named after the HTTP verbs (e.g., get(), post(), delete()).
Basic Implementation
Define a class that inherits from MethodView and implement the methods for the HTTP verbs you want to support. Use as_view() to convert the class into a view function for registration.
from flask import Flask, session, redirect, url_for
from flask.views import MethodView
app = Flask(__name__)
class CounterAPI(MethodView):
def get(self):
return str(session.get("counter", 0))
def post(self):
session["counter"] = session.get("counter", 0) + 1
return redirect(url_for("counter"))
# Register the view with a unique name
app.add_url_rule(
"/counter",
view_func=CounterAPI.as_view("counter")
)
Composing Views with Inheritance
You can use standard Python inheritance to share logic across different API endpoints. MethodView automatically detects methods defined in parent classes.
from flask.views import MethodView
class GetView(MethodView):
def get(self):
return "GET"
class DeleteView(MethodView):
def delete(self):
return "DELETE"
# This view handles both GET and DELETE
class GetDeleteView(GetView, DeleteView):
pass
app.add_url_rule("/", view_func=GetDeleteView.as_view("index"))
Asynchronous Handlers
If you are running on an ASGI server, MethodView supports async handler methods. The dispatch_request method uses current_app.ensure_sync to handle both synchronous and asynchronous methods correctly.
import asyncio
from flask.views import MethodView
class AsyncMethodView(MethodView):
async def get(self):
await asyncio.sleep(0)
return "GET"
async def post(self):
await asyncio.sleep(0)
return "POST"
app.add_url_rule("/async", view_func=AsyncMethodView.as_view("async_api"))
Applying Decorators
To apply decorators (like authentication or logging) to a class-based view, define them in the decorators class attribute. Applying decorators directly to the class using @decorator syntax will not work for the generated view function.
from flask.views import MethodView
def user_required(f):
# implementation...
return f
class SecureView(MethodView):
decorators = [user_required]
def get(self):
return "Secure Content"
app.add_url_rule("/secure", view_func=SecureView.as_view("secure"))
Performance Optimization
By default, MethodView creates a new instance of the class for every request. If your view is stateless and has expensive initialization, you can set init_every_request to False to reuse a single instance.
from flask.views import MethodView
class EfficientView(MethodView):
init_every_request = False
def __init__(self):
# This runs only once
self.data = "Loaded once"
def get(self):
return self.data
app.add_url_rule("/efficient", view_func=EfficientView.as_view("efficient"))
Troubleshooting
HEAD Request Fallback
If a client sends a HEAD request and your MethodView does not implement a head() method, it will automatically fall back to using the get() method if it exists.
Automatic Method Detection
The methods attribute is automatically populated during class creation by __init_subclass__. It scans for methods named after HTTP verbs (defined in http_method_funcs in src/flask/views.py). If you need to restrict the methods manually, you can override the methods attribute:
class RestrictedView(MethodView):
# Only allow GET even if post() is defined
methods = ["GET"]
def get(self):
return "Allowed"
def post(self):
return "Hidden"
Unimplemented Methods
If a request is made using an HTTP method that is not implemented in your class (and no fallback exists), dispatch_request will raise an AssertionError (or trigger a 405 Method Not Allowed if handled by the app routing). Ensure all expected verbs are implemented or handled by inheritance.