Skip to main content

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.