E

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.

SkillCommunitybackendv1.0.0MIT
0 views0 copies

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

PatternDescriptionWhen to Use
Feature RoutersGroup by domain (users, orders, products)Most applications
Versioned RoutersSeparate routers per API versionPublic APIs with versioning
Role-Based RoutersSeparate admin/public endpointsMulti-tenant apps
Nested RoutersSub-routers for resource relationshipsComplex hierarchies

Dependency Injection

DependencyScopeExample
Database SessionPer-requestDepends(get_db)
Current UserPer-requestDepends(get_current_user)
SettingsSingletonDepends(get_settings)
Cache ClientSingletonDepends(get_redis)
Rate LimiterPer-requestDepends(rate_limit(10, 60))
PaginationPer-requestDepends(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

ParameterDescriptionDefault
router_prefixBase URL prefix for all routes/api/v2
auth_schemeAuthentication: jwt, oauth2, api_keyjwt
pagination_defaultDefault page size20
pagination_maxMaximum page size100
cors_originsAllowed CORS origins["*"]
rate_limitRequests per minute per IP60
docs_urlSwagger UI path/docs

Best Practices

  1. 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.

  2. Define separate Pydantic models for request and response — Use UserCreate (input validation), UserUpdate (partial, all optional), and UserResponse (output serialization, excludes password). Never expose internal models directly as API responses.

  3. 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.

  4. Use response_model on every endpoint for automatic documentation — The response_model parameter drives OpenAPI schema generation, automatic response serialization, and field filtering. It also prevents accidentally exposing internal fields.

  5. 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.pyrouters/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.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates