FastAPI Views
Class-based views, CRUD utilities, and production-ready patterns for FastAPI.
FastAPI Views brings the ergonomics of class-based views (CBVs) to FastAPI, following conventions familiar from Django REST Framework while staying true to FastAPI's type-safe, dependency-injection model. It ships a full suite of building blocks — from low-level View classes to fully-wired GenericViewSet with pagination, filtering, and sorting — so you can focus on business logic rather than HTTP plumbing.
Why FastAPI Views?
FastAPI's function-based approach is powerful but can become repetitive as an API grows. FastAPI Views solves several common pain points:
Reduce boilerplate. A complete CRUD resource — list, create, retrieve, update, partial update, delete — is defined by inheriting a single class and implementing a handful of methods. All routes, HTTP methods, status codes, and OpenAPI operation IDs are wired up automatically.
Enforce consistency. Shared logic (authentication, logging, error handling) lives in the class and is applied uniformly across every action. Response serialization, status codes, and error shapes are standardized across the whole API.
Correct HTTP semantics out of the box. POST returns 201 Created, DELETE returns 204 No Content, PUT/PATCH detail routes accept a primary key, and Location headers are set on creation — all without any extra code.
RFC 9457 Problem Details. Every error response follows the Problem Details standard with machine-readable type, title, status, and detail fields. Custom error classes are trivial to create and are automatically reflected in the OpenAPI spec.
ORM-agnostic. Generic views use a simple repository protocol. Plug in SQLAlchemy, Motor, plain dicts, or any data source — the view layer does not care.
Batteries included. Advanced DRF-style filters, cursor and page-number pagination, field projection, Server-Sent Events, Prometheus metrics, and OpenTelemetry tracing are all available as opt-in add-ons.
Installation
Optional extensions
| Extra | What it adds |
|---|---|
uvloop |
uvloop event loop for better async performance |
prometheus |
Prometheus metrics middleware (/metrics endpoint) |
uvicorn |
uvicorn ASGI server |
opentelemetry |
OpenTelemetry tracing instrumentation |
cli |
CLI tool for generating static OpenAPI JSON/YAML files |
Install all extras at once:
Quick start
from typing import ClassVar, Optional
from uuid import UUID
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi_views import ViewRouter, configure_app
from fastapi_views.views.viewsets import AsyncAPIViewSet
class ItemSchema(BaseModel):
id: UUID
name: str
price: int
class ItemViewSet(AsyncAPIViewSet):
api_component_name = "Item"
response_schema = ItemSchema
# In-memory store — swap for a real repository in production
items: ClassVar[dict[UUID, ItemSchema]] = {}
async def list(self) -> list[ItemSchema]:
return list(self.items.values())
async def create(self, item: ItemSchema) -> ItemSchema:
self.items[item.id] = item
return item
async def retrieve(self, id: UUID) -> Optional[ItemSchema]:
return self.items.get(id)
async def update(self, id: UUID, item: ItemSchema) -> ItemSchema:
self.items[id] = item
return item
async def destroy(self, id: UUID) -> None:
self.items.pop(id, None)
router = ViewRouter(prefix="/items")
router.register_view(ItemViewSet)
app = FastAPI(title="My API")
app.include_router(router)
configure_app(app)
This registers the following routes automatically:
| Method | Path | Action | Status code |
|---|---|---|---|
GET |
/items |
list |
200 |
POST |
/items |
create |
201 |
GET |
/items/{id} |
retrieve |
200 |
PUT |
/items/{id} |
update |
200 |
DELETE |
/items/{id} |
destroy |
204 |
Features
Class-based views
Three levels of abstraction let you choose the right amount of automation:
View— low-level base class. You control routing with@get,@post,@put,@patch,@deletedecorators and returnResponseobjects directly. Zero magic.APIView— adds Pydantic v2 serialization and error handling. Return plain dicts or model instances; the view serializes them automatically.ViewSet/APIViewSet— combines multiple CRUD actions into one class. Mix and match with provided mixin classes (ListAPIView,CreateAPIView, etc.) for exactly the surface you need.
Generic views with the repository pattern
GenericViewSet and AsyncGenericViewSet implement all CRUD logic for you. Provide a repository object that satisfies the Repository / AsyncRepository protocol and the view handles the rest — including 409 Conflict on duplicate creates and 404 Not Found on missing resources. Lifecycle hooks (before_create, after_create, before_update, after_update) let you add custom logic without overriding entire actions.
See Generic Views for a full example.
Filters, pagination, and sorting
The Filter system mirrors Django REST Framework's FilterSet API:
ModelFilter— filter by model field values (e.g.?name=Alice)OrderingFilter— sort by whitelisted fields using?sort=nameor?sort=-created_atSearchFilter— full-text search across multiple fields with?query=…PaginationFilter— page-number pagination returning aNumberedPageTokenPaginationFilter— cursor-based pagination returning aTokenPageFieldsFilter— sparse fieldsets; return only requested fields with?fields=id,nameFilter— convenience class combining all of the above
Built-in resolvers for SQLAlchemy and plain Python objects translate filter objects into queries with zero glue code.
See Filters for usage details.
RFC 9457 Problem Details error handling
Every error response is an ErrorDetails model conforming to RFC 9457:
{
"type": "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"detail": "The requested resource was not found.",
"instance": "/items/abc",
"errors": []
}
Built-in error classes cover the most common cases: NotFound, BadRequest, Conflict, Unauthorized, Forbidden, Throttled, UnprocessableEntity, InternalServerError, and Unavailable. Creating a custom error class is as simple as subclassing APIError:
from fastapi_views.exceptions import APIError
from starlette.status import HTTP_402_PAYMENT_REQUIRED
class PaymentRequired(APIError):
"""Payment is required to access this resource."""
status = HTTP_402_PAYMENT_REQUIRED
The error's Pydantic model is automatically registered in the OpenAPI spec for every route that may raise it.
Smart serialization
Serialization uses Pydantic v2's TypeAdapter, which is cached per schema type. This means the first request to an endpoint pays the reflection cost; subsequent requests reuse the cached serializer. All standard Pydantic options (by_alias, include, exclude, context) are supported.
Server-Sent Events (SSE)
ServerSideEventsAPIView and the @sse_route decorator make streaming real-time events straightforward. The view handles content-type negotiation, connection headers, and SSE framing automatically. Data is serialized and validated using the same Pydantic pipeline as regular views.
See Server-Sent Events.
OpenTelemetry integration
When opentelemetry-sdk is installed, configure_app automatically injects the active trace's correlation_id into every error response. This makes it trivial to correlate an error seen by a user with a span in your tracing backend.
See OpenTelemetry.
Prometheus metrics
When the prometheus extra is installed, configure_app mounts a /metrics endpoint that exposes standard HTTP request metrics (request count, latency histogram, in-flight requests) compatible with prometheus_client.
configure_app — one-call setup
configure_app(app) wires up:
- RFC 9457 error handlers for
APIError, FastAPI'sRequestValidationError, and unhandled exceptions - Prometheus middleware (if
starlette-exporteris installed) - OpenTelemetry instrumentation (if
opentelemetry-sdkis installed)
This single call replaces dozens of lines of middleware and exception handler boilerplate.
ORM-agnostic design
FastAPI Views has no dependency on any ORM. Generic views interact with data through the Repository protocol, which is trivially satisfied by any object exposing create, get, list, update_one, delete, and get_filtered_page methods. Pair it with SQLAlchemy, Tortoise ORM, MongoDB Motor, or a plain in-memory dict.
Both async and sync support
Every view class has an Async and a synchronous variant (AsyncListAPIView / ListAPIView, AsyncAPIViewSet / APIViewSet, etc.). Sync endpoints are run in a thread pool automatically by Starlette, so they are safe to use alongside async code.
OpenAPI operation ID simplification
Operation IDs in the generated OpenAPI spec follow an {action}_{component_name} convention (e.g., list_item, create_item, retrieve_item). This makes generated client and SDK names readable rather than the long, path-derived defaults that FastAPI produces.
CLI
Generate a static openapi.json or openapi.yaml file without starting a server:
# Install the CLI extra
pip install 'fastapi-views[cli]'
# Export the spec
fastapi-views export myapp:app --output openapi.json
Project status
FastAPI Views is actively maintained, fully type-checked with mypy, linted with Ruff, and security-scanned with Bandit. It supports Python 3.10 and above.