类DRF风格的FastAPI工具包
Project description
FastAPI REST Toolkit
A Django REST Framework style toolkit for FastAPI, providing a clean and elegant way to build RESTful APIs.
Features
- ViewSet: DRF-like ViewSet with full CRUD operations support
- Router: Automatic route registration, simplified routing configuration
- Authentication System: Flexible authentication mechanisms (Bearer Token, etc.)
- Permission System: Flexible permission control (AllowAny, IsAuthenticated, IsAdmin)
- Filters: Support for search, ordering, and CRUD Plus filtering
- Throttling: Built-in rate limiting with Redis storage support
- Pagination: Built-in LimitOffset pagination
- Relation Loading: Support for SQLAlchemy relationship data preloading
- Schema Tools: Automatically generate Pydantic Schemas from SQLAlchemy models
Installation
pip install fastapi-rest-toolkit
Or install the full version with Redis dependencies:
pip install fastapi-rest-toolkit[all]
Quick Start
Complete Example
from fastapi import FastAPI
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import String, DateTime, func
from fastapi_rest_toolkit import (
DefaultRouter,
ViewSet,
CRUDService,
AllowAny,
IsAuthenticated,
AsyncRedisSimpleRateThrottle,
)
from sqlalchemy_crud_plus import CRUDPlus
from app.db.redis import redis_client
# 1. Define SQLAlchemy model
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
email: Mapped[str] = mapped_column(String(100), unique=True)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
# 2. Define Schemas (manually or auto-generated)
from pydantic import BaseModel
class UserRead(BaseModel):
id: int
email: str
name: str
class UserCreate(BaseModel):
email: str
name: str
class UserUpdate(BaseModel):
email: str | None = None
name: str | None = None
# 3. Define ViewSet
class UserViewSet(ViewSet):
# read_schema = UserRead
# create_schema = UserCreate
# update_schema = UserUpdate
model = User # only define model for sqlalchemy
# Permission configuration
permission_classes = (AllowAny, IsAuthenticated)
# Search and ordering
search_fields = ("email", "name")
ordering_fields = ("id", "email", "name", "created_at")
# Throttle configuration
throttle_classes = (AsyncRedisSimpleRateThrottle(redis=redis_client),)
def __init__(self):
user_crud = CRUDPlus(User)
self.service = CRUDService(crud=user_crud, model=User)
# 4. Create database session
DATABASE_URL = "sqlite+aiosqlite:///./app.db"
engine = create_async_engine(DATABASE_URL, echo=False)
async_session = async_sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)
async def get_session():
async with async_session() as session:
yield session
# 5. Register routes
app = FastAPI()
router = DefaultRouter()
router.register(
"users",
UserViewSet,
get_session=get_session,
tags=["users"],
)
app.include_router(router.router, prefix="/api")
Authentication System
Support custom authentication classes by extending BaseAuthentication:
from fastapi import HTTPException, status
from fastapi_rest_toolkit.authentication import BearerAuthentication
from fastapi_rest_toolkit.request import FRFRequest
from fastapi_rest_toolkit.contextvar import session_var
class UserAuthentication(BearerAuthentication):
async def authenticate(self, request: FRFRequest) -> tuple[Any, Any]:
session = session_var.get()
token = self.get_token(request)
if not token:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication"
)
# Verify token and get user
user = await self.verify_token(token, session)
return user, token
# Use in ViewSet
class UserViewSet(ViewSet):
authentication_classes = (UserAuthentication,)
permission_classes = (IsAuthenticated,)
Auto-generate Schemas
Use utility functions to automatically generate Pydantic Schemas from SQLAlchemy models:
from fastapi_rest_toolkit.utils import sqlalchemy_model_to_pydantic
from app.models.user import User
# Auto-generate schemas
UserRead = sqlalchemy_model_to_pydantic(User, name="UserRead")
UserCreate = sqlalchemy_model_to_pydantic(User, name="UserCreate", exclude={"id"})
UserUpdate = sqlalchemy_model_to_pydantic(User, name="UserUpdate", optional=True)
Relationship Data Loading
Support loading related data (using selectinload):
class UserViewSet(ViewSet):
load_strategies = ("posts",) # Auto-load posts relationship
Permission Control
from fastapi_rest_toolkit import AllowAny, IsAuthenticated, IsAdmin
class ProtectedViewSet(ViewSet):
permission_classes = (IsAuthenticated,) # Requires login
class AdminViewSet(ViewSet):
permission_classes = (IsAdmin,) # Requires admin privileges
Custom Permission Class:
from fastapi_rest_toolkit.permissions import BasePermission
from fastapi_rest_toolkit.request import FRFRequest
class IsOwner(BasePermission):
async def has_permission(self, request: FRFRequest, viewset) -> bool:
return request.user and request.user.id == int(request.path_params["id"])
Pagination
Built-in LimitOffsetPagination support:
from fastapi_rest_toolkit import ViewSet, LimitOffsetPagination
class CustomPagination(LimitOffsetPagination):
default_limit = 10
max_limit = 50
class UserViewSet(ViewSet):
pagination = CustomPagination()
API Usage Example:
GET /api/users?limit=10&offset=0
Search and Ordering
class UserViewSet(ViewSet):
# Searchable fields
search_fields = ("name", "email")
# Orderable fields
ordering_fields = ("id", "name", "created_at")
API Usage Example:
# Search
GET /api/users?search=john
# Order
GET /api/users?ordering=-created_at
# Combined
GET /api/users?search=john&ordering=name
Throttle Configuration
from fastapi_rest_toolkit.throttle import AsyncRedisSimpleRateThrottle
from app.db.redis import redis_client
class UserViewSet(ViewSet):
throttle_classes = (AsyncRedisSimpleRateThrottle(
redis=redis_client,
rate="100/hour" # Optional, defaults to 100/hour
),)
Available Throttle Classes:
SimpleRateThrottle- Simple rate limiting (in-memory storage)AnonRateThrottle- Anonymous user rate limitingAsyncRedisSimpleRateThrottle- Async rate limiting based on Redis
Exception Handling
from fastapi import Request
from fastapi.responses import JSONResponse
from sqlalchemy.exc import IntegrityError
async def integrity_error_handler(request: Request, exc: IntegrityError) -> JSONResponse:
"""Handle database integrity constraint errors"""
error_message = str(exc.orig)
if "UNIQUE constraint failed" in error_message:
parts = error_message.split(":")
if len(parts) > 1:
constraint_info = parts[1].strip()
field = constraint_info.split(".")[-1] if "." in constraint_info else constraint_info
detail = f"{field} already exists"
else:
detail = error_message
return JSONResponse(
status_code=400,
content={"detail": detail, "error_type": "integrity_error"}
)
# Register exception handler
app.add_exception_handler(IntegrityError, integrity_error_handler)
Custom Method Behavior
Customize behavior by overriding methods:
class UserViewSet(ViewSet):
async def create(self, request: FRFRequest):
# Custom create logic
data = await request.json()
# ... custom handling
return await super().create(request)
async def destroy(self, request: FRFRequest, id: int):
# Custom delete logic
# ... check permissions, etc.
return await super().destroy(request, id)
Component Documentation
ViewSet
Provides standard CRUD operation interfaces:
| Method | Route | Description |
|---|---|---|
list() |
GET /api/users |
Get list (supports search, ordering, pagination) |
retrieve() |
GET /api/users/{id} |
Get single object |
create() |
POST /api/users |
Create object |
update() |
PUT/PATCH /api/users/{id} |
Update object |
destroy() |
DELETE /api/users/{id} |
Delete object |
ViewSet Configuration Options:
class ViewSet:
# Schema configuration
read_schema: Type[BaseModel] # Schema for reading data
create_schema: Type[BaseModel] # Schema for creating data
update_schema: Type[BaseModel] # Schema for updating data
# Authentication and permissions
authentication_classes: Sequence[Type[BaseAuthentication]] # Authentication classes
permission_classes: Sequence[Type[BasePermission]] # Permission classes
# Filtering and ordering
search_fields: Sequence[str] # Searchable fields
ordering_fields: Sequence[str] # Orderable fields
filter_backends: Sequence # Filter backends
# Pagination and throttling
pagination: LimitOffsetPagination # Pagination configuration
throttle_classes: Sequence[Type[BaseThrottle]] # Throttle classes
throttle_scope: str # Throttle scope
# Relationship loading
load_strategies: Sequence[str] # Preloaded relationship fields
join_conditions: Any # Join conditions
# Allowed HTTP methods
allowed_methods: Sequence[str] # Defaults to all CRUD methods
Authentication Classes
BaseAuthentication- Base authentication classBearerAuthentication- Base Bearer Token authentication class
Custom Authentication:
from fastapi_rest_toolkit.authentication import BaseAuthentication
from fastapi_rest_toolkit.request import FRFRequest
class CustomAuth(BaseAuthentication):
async def authenticate(self, request: FRFRequest) -> tuple[Any, Any]:
# Return (user, auth) or (None, None)
pass
Permission Classes
AllowAny- Allow all accessIsAuthenticated- Requires authenticationIsAdmin- Requires admin privilegesBasePermission- Custom permission base class
Filters
SearchFilterBackend- Search filtering (usingsearchquery parameter)OrderingFilterBackend- Ordering (usingorderingquery parameter)CRUDPlusFilterBackend- CRUD Plus filtering
Throttle Classes
SimpleRateThrottle- Simple rate limiting (in-memory storage)AnonRateThrottle- Anonymous user rate limitingAsyncRedisSimpleRateThrottle- Async rate limiting based on Redis
Router
DefaultRouter automatically registers routes for ViewSets:
router = DefaultRouter()
router.register(
prefix="users", # URL prefix
viewset=UserViewSet, # ViewSet class
get_session=get_session, # Database session getter function
tags=["users"], # OpenAPI tags
)
app.include_router(router.router, prefix="/api")
Utility Functions
sqlalchemy_model_to_pydantic()- Generate Pydantic Schema from SQLAlchemy model
Complete Demo
See the demo directory for complete usage examples, including:
- Database model definitions
- JWT authentication implementation
- Redis throttle configuration
- Exception handling
- Multiple ViewSet implementations
Run the example:
cd demo
uvicorn main:app --reload
Access API documentation at: http://127.0.0.1:8000/docs
License
MIT License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_rest_toolkit-0.0.6.tar.gz.
File metadata
- Download URL: fastapi_rest_toolkit-0.0.6.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a415094856335fdb6fe52066b78e9bfe2fc753ebc80091675dc6e2d535bbad5
|
|
| MD5 |
98525a4edc588eccb5888d55f71bd1b6
|
|
| BLAKE2b-256 |
15555e54b8402b587d534a972d3569bab0a5a9502dff1b05fb168ea2a3fc44f7
|
File details
Details for the file fastapi_rest_toolkit-0.0.6-py3-none-any.whl.
File metadata
- Download URL: fastapi_rest_toolkit-0.0.6-py3-none-any.whl
- Upload date:
- Size: 17.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dea765eccfa26e3bdf6a87e202c6136484b876080ac464fd7393d43030efc8c
|
|
| MD5 |
8c7e11047a1ece2d82c50518a12bb33d
|
|
| BLAKE2b-256 |
d29e79094c714a025c2df2ce53d072c6ceab27ae31972cfab430f19eae87fac6
|