Building RESTful APIs with MethodView
To implement RESTful resources in this project, use the MethodView class to map HTTP methods directly to class instance methods. This approach organizes your API logic by resource rather than by route.
Basic Implementation
Define a class that inherits from MethodView and implement methods named after the HTTP verbs (lowercase) you want to handle.
from flask.views import MethodView
class Index(MethodView):
def get(self):
return "GET"
def post(self):
return "POST"
# Register the view using as_view()
app.add_url_rule("/", view_func=Index.as_view("index"))
The as_view method converts the class into a view function. The name passed to as_view (e.g., "index") is used for URL building with url_for.
Handling URL Parameters (CRUD Pattern)
For RESTful resources that require both collection and item access, you can define optional arguments in your methods and register multiple URL rules.
class UserAPI(MethodView):
def get(self, user_id=None):
if user_id is None:
return "List all users"
return f"Details for user {user_id}"
def post(self):
return "Create a new user"
def put(self, user_id):
return f"Update user {user_id}"
def delete(self, user_id):
return f"Delete user {user_id}"
user_view = UserAPI.as_view("user_api")
app.add_url_rule("/users/", defaults={"user_id": None}, view_func=user_view, methods=["GET"])
app.add_url_rule("/users/", view_func=user_view, methods=["POST"])
app.add_url_rule("/users/<int:user_id>", view_func=user_view, methods=["GET", "PUT", "DELETE"])
Asynchronous Support
MethodView supports asynchronous handlers. If you define your methods with async def, the dispatcher will automatically handle them using current_app.ensure_sync.
import asyncio
from flask.views import MethodView
class AsyncUserAPI(MethodView):
async def get(self):
await asyncio.sleep(0)
return "Async GET"
app.add_url_rule("/async", view_func=AsyncUserAPI.as_view("async_user"))
Extending Resources with Inheritance
MethodView automatically detects implemented HTTP methods by inspecting the class and its bases. You can extend existing resources to add or override functionality.
class BaseResource(MethodView):
def get(self):
return "Base GET"
class ExtendedResource(BaseResource):
def post(self):
return "Extended POST"
def delete(self):
return "Extended DELETE"
# ExtendedResource will support GET (from base), POST, and DELETE
app.add_url_rule("/extended", view_func=ExtendedResource.as_view("extended"))
Applying Decorators
Because as_view generates the view function, applying decorators directly to the class using @decorator syntax will not work. Instead, use the decorators class attribute.
def auth_required(f):
def wrapper(*args, **kwargs):
# implementation
return f(*args, **kwargs)
return wrapper
class SecureAPI(MethodView):
decorators = [auth_required]
def get(self):
return "Secure Data"
Optimizing Performance
By default, init_every_request is True, meaning a new instance of the class is created for every request. If your view does not store request-specific data on self, you can set it to False to reuse the same instance.
class FastView(MethodView):
init_every_request = False
def get(self):
return "Efficient response"
Troubleshooting
- HEAD Requests: If you implement
getbut nothead,MethodViewautomatically falls back to thegetmethod forHEADrequests. - Unimplemented Methods: If a request is made with a method that is not implemented in the class (and not handled by the
HEADfallback), the dispatcher will raise anAssertionError. Ensure youradd_url_ruleonly includes methods you have implemented. - Method Detection: The
methodsattribute is automatically populated during class creation. If you manually definemethodson the class, it will override the automatic detection.