Expert FastAPI Router Patterns Toolkit
Professional-grade skill designed for fastAPI routers with CRUD operations and authentication. Built for Claude Code with best practices and real-world patterns.
FastAPI Router Patterns Toolkit
Production-ready FastAPI routing patterns covering modular router organization, dependency injection, middleware, error handling, authentication, and API versioning for scalable backend applications.
When to Use This Skill
Choose FastAPI Router Patterns when:
- Organizing FastAPI applications with many endpoints
- Implementing authentication and authorization middleware
- Setting up dependency injection for database, cache, and services
- Building versioned APIs with backward compatibility
- Creating consistent error handling across endpoints
Consider alternatives when:
- Building simple scripts — use plain functions
- Need Django-style ORM — use Django REST Framework
- Building GraphQL — use Strawberry or Ariadne
Quick Start
# Activate FastAPI router patterns claude skill activate expert-fastapi-router-patterns-toolkit # Organize routes claude "Organize my FastAPI app into modular routers with dependency injection" # Add authentication claude "Add JWT authentication middleware to the FastAPI API"
Example: Modular Router Structure
# app/main.py from fastapi import FastAPI from app.routers import users, orders, products from app.middleware import error_handler, request_logger from app.dependencies import get_db app = FastAPI(title="Store API", version="2.0.0") # Include routers with prefixes and tags app.include_router(users.router, prefix="/api/v2/users", tags=["Users"]) app.include_router(orders.router, prefix="/api/v2/orders", tags=["Orders"]) app.include_router(products.router, prefix="/api/v2/products", tags=["Products"]) # Global middleware app.middleware("http")(request_logger) app.add_exception_handler(Exception, error_handler)
# app/routers/users.py from fastapi import APIRouter, Depends, HTTPException, status, Query from app.dependencies import get_db, get_current_user from app.models.user import UserCreate, UserResponse, UserUpdate from app.services.user_service import UserService router = APIRouter() @router.get("/", response_model=list[UserResponse]) async def list_users( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), db=Depends(get_db), current_user=Depends(get_current_user), ): service = UserService(db) return await service.list_users(skip=skip, limit=limit) @router.get("/{user_id}", response_model=UserResponse) async def get_user( user_id: str, db=Depends(get_db), ): service = UserService(db) user = await service.get_by_id(user_id) if not user: raise HTTPException(status_code=404, detail="User not found") return user @router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED) async def create_user( user_data: UserCreate, db=Depends(get_db), ): service = UserService(db) return await service.create(user_data) @router.patch("/{user_id}", response_model=UserResponse) async def update_user( user_id: str, user_data: UserUpdate, db=Depends(get_db), current_user=Depends(get_current_user), ): service = UserService(db) return await service.update(user_id, user_data)
Core Concepts
Router Organization
| Pattern | Description | When to Use |
|---|---|---|
| Feature Routers | Group by domain (users, orders, products) | Most applications |
| Versioned Routers | Separate routers per API version | Public APIs with versioning |
| Role-Based Routers | Separate admin/public endpoints | Multi-tenant apps |
| Nested Routers | Sub-routers for resource relationships | Complex hierarchies |
Dependency Injection
| Dependency | Scope | Example |
|---|---|---|
| Database Session | Per-request | Depends(get_db) |
| Current User | Per-request | Depends(get_current_user) |
| Settings | Singleton | Depends(get_settings) |
| Cache Client | Singleton | Depends(get_redis) |
| Rate Limiter | Per-request | Depends(rate_limit(10, 60)) |
| Pagination | Per-request | Depends(pagination_params) |
# Dependency injection patterns # Database session with cleanup async def get_db(): db = SessionLocal() try: yield db finally: await db.close() # Authenticated user dependency async def get_current_user( token: str = Depends(oauth2_scheme), db=Depends(get_db), ) -> User: payload = decode_jwt(token) user = await db.get(User, payload["sub"]) if not user: raise HTTPException(status_code=401, detail="Invalid token") return user # Role-based authorization dependency def require_role(*roles: str): async def check_role(user: User = Depends(get_current_user)): if user.role not in roles: raise HTTPException(status_code=403, detail="Insufficient permissions") return user return check_role # Usage: @router.delete("/{user_id}") async def delete_user( user_id: str, admin: User = Depends(require_role("admin")), ): ... # Reusable pagination def pagination_params( skip: int = Query(0, ge=0), limit: int = Query(20, ge=1, le=100), ): return {"skip": skip, "limit": limit}
Configuration
| Parameter | Description | Default |
|---|---|---|
router_prefix | Base URL prefix for all routes | /api/v2 |
auth_scheme | Authentication: jwt, oauth2, api_key | jwt |
pagination_default | Default page size | 20 |
pagination_max | Maximum page size | 100 |
cors_origins | Allowed CORS origins | ["*"] |
rate_limit | Requests per minute per IP | 60 |
docs_url | Swagger UI path | /docs |
Best Practices
-
Use dependency injection for everything, never import directly — Pass database connections, configuration, authentication, and services through
Depends(). This makes endpoints testable (inject mocks), configurable, and follows the dependency inversion principle. -
Define separate Pydantic models for request and response — Use
UserCreate(input validation),UserUpdate(partial, all optional), andUserResponse(output serialization, excludes password). Never expose internal models directly as API responses. -
Implement a service layer between routes and database — Routers should only handle HTTP concerns (status codes, headers). Business logic belongs in service classes that are injected via dependencies. This keeps routes thin and business logic testable without HTTP overhead.
-
Use
response_modelon every endpoint for automatic documentation — Theresponse_modelparameter drives OpenAPI schema generation, automatic response serialization, and field filtering. It also prevents accidentally exposing internal fields. -
Handle errors consistently with custom exception handlers — Create domain exceptions (UserNotFound, InsufficientBalance) and map them to HTTP responses in a global exception handler. This centralizes error formatting and keeps routes clean of try/except blocks.
Common Issues
Circular import errors between routers, models, and dependencies. Organize imports to flow in one direction: main.py → routers/ → services/ → models/. Use TYPE_CHECKING blocks for type hints that would create circular imports, and use string forward references.
Database session leaks when endpoints raise exceptions. Always use yield in database dependency functions with a finally block for cleanup. FastAPI's dependency injection guarantees the finally block runs even when exceptions propagate.
Swagger docs become unwieldy with many endpoints. Use router tags to group related endpoints. Add description parameters to routers and endpoints. Use include_in_schema=False for internal endpoints. Consider separating public and admin API docs with different FastAPI app instances.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.