REST resources repeat the same GET/POST/PATCH/DELETE structure, which classes express compactly.
Function views are Flask's default, but for REST-style resources a `MethodView` maps each HTTP method to a method of the class:
class ItemAPI(MethodView):
def get(self, item_id): ...
def patch(self, item_id): ...
def delete(self, item_id): ...Register it with app.add_url_rule("/items/<int:item_id>", view_func=ItemAPI.as_view("item")). Flask reads the methods the class defines and sets the allowed HTTP methods automatically; others get 405.
A common pattern uses two URLs for one resource type: a collection (/items/ with get to list and post to create) and an item (/items/<id> with get, patch, delete). A small helper function can register both for any model, which is where classes shine: subclass, set model = User, and reuse everything.
Details:
as_view(name, *args)passes arguments to__init__; setinit_every_request = Falseto create the instance once instead of per request (only safe if it holds no per-request state).decorators = [login_required]as a class attribute applies decorators to the generated view function.- The plain
Viewbase class with adispatch_requestmethod is the lower-level alternative.
For larger APIs, extensions such as Flask-Smorest or APIFlask add request validation, serialization and OpenAPI docs on top of this pattern. If an API is your main goal and you are starting fresh, also consider FastAPI.
Example
from flask import Flask, request
from flask.views import MethodView
app = Flask(__name__)
ITEMS = {1: {"name": "pen"}}
class ItemCollection(MethodView):
def get(self):
return [{"id": i, **v} for i, v in ITEMS.items()]
def post(self):
new_id = max(ITEMS, default=0) + 1
ITEMS[new_id] = {"name": request.get_json()["name"]}
return {"id": new_id}, 201
class Item(MethodView):
def get(self, item_id):
return ITEMS.get(item_id) or ({"error": "not found"}, 404)
def delete(self, item_id):
ITEMS.pop(item_id, None)
return "", 204
app.add_url_rule("/items/", view_func=ItemCollection.as_view("items"))
app.add_url_rule("/items/<int:item_id>", view_func=Item.as_view("item"))
c = app.test_client()
print(c.post("/items/", json={"name": "ink"}).json, c.get("/items/").json)
# {'id': 2} [{'id': 1, 'name': 'pen'}, {'id': 2, 'name': 'ink'}]
print(c.delete("/items/1").status_code, c.put("/items/1").status_code) # 204 405Remember
- MethodView maps HTTP methods to class methods; allowed methods are inferred
- Register with add_url_rule(path, view_func=Cls.as_view("name"))
- Collection and item views together form a REST resource
Watch out for
- Storing per-request data on self with init_every_request = False, which shares it across requests.