Skip to main content

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 get but not head, MethodView automatically falls back to the get method for HEAD requests.
  • Unimplemented Methods: If a request is made with a method that is not implemented in the class (and not handled by the HEAD fallback), the dispatcher will raise an AssertionError. Ensure your add_url_rule only includes methods you have implemented.
  • Method Detection: The methods attribute is automatically populated during class creation. If you manually define methods on the class, it will override the automatic detection.